Import of WPA supplicant 0.4.8

This commit is contained in:
Sam Leffler 2006-03-07 05:26:33 +00:00
parent e00d94fa7c
commit 4e0922e888
156 changed files with 32587 additions and 6597 deletions

View file

@ -1,32 +1,294 @@
ChangeLog for wpa_supplicant
2005-06-10 - v0.3.9
* modified the EAP workaround that accepts EAP-Success with incorrect
Identifier to be even less strict about verification in order to
interoperate with some authentication servers
* fixed RSN IE in 4-Way Handshake message 2/4 for the case where
Authenticator rejects PMKSA caching attempt and the driver is not
using assoc_info events
* fixed a possible double free in EAP-TTLS fast-reauthentication when
identity or password is entered through control interface
* added -P<pid file> argument for wpa_supplicant to write the current
process id into a file
* driver_madwifi: fixed association in plaintext mode
* driver_madwifi: added preliminary support for compiling against 'BSD'
branch of madwifi CVS tree
* added EAP workaround for PEAPv1 session resumption: allow outer,
2006-02-08 - v0.4.8
* fixed PC/SC code to use correct length for GSM AUTH command buffer
and to not use pioRecvPci with SCardTransmit() calls; these were not
causing visible problems with pcsc-lite, but Windows Winscard.dll
refused the previously used parameters; this fixes EAP-SIM and
EAP-AKA authentication using SIM/USIM card under Windows
* added support for EAP-FAST key derivation using other ciphers than
RC4-128-SHA for authentication and AES128-SHA for provisioning
* fixed EAP-SIM and EAP-AKA pseudonym and fast re-authentication to
decrypt AT_ENCR_DATA attributes correctly
* added support for configuring CA certificate as DER file and as a
configuration blob
* fixed private key configuration as configuration blob and added
support for using PKCS#12 as a blob
* fixed cygwin build
* added support for loading trusted CA certificates from Windows
certificate store: ca_cert="cert_store://<name>", where <name> is
likely CA (Intermediate CA certificates) or ROOT (root certificates)
* fixed TLS library deinitialization after RSN pre-authentication not
to disable TLS library for normal authentication
* fixed PMKSA cache processing not to trigger deauthentication if the
current PMKSA cache entry is replaced with a valid new entry
* fixed PC/SC initialization for ap_scan != 1 modes (this fixes
EAP-SIM and EAP-AKA with real SIM/USIM card when using ap_scan=0 or
ap_scan=2)
* do not try to use USIM APDUs when initializing PC/SC for SIM card
access for a network that has not enabled EAP-AKA
2005-11-20 - v0.4.7 (beginning of 0.4.x stable releases)
* l2_packet_pcap: fixed wired IEEE 802.1X authentication with libpcap
and WinPcap to receive frames sent to PAE group address
* disable EAP state machine when IEEE 802.1X authentication is not used
in order to get rid of bogus "EAP failed" messages
* fixed OpenSSL error reporting to go through all pending errors to
avoid confusing reports of old errors being reported at later point
during handshake
* fixed configuration file updating to not write empty variables
(e.g., proto or key_mgmt) that the file parser would not accept
* fixed ADD_NETWORK ctrl_iface command to use the same default values
for variables as empty network definitions read from config file
would get
* fixed EAP state machine to not discard EAP-Failure messages in many
cases (e.g., during TLS handshake)
* fixed a infinite loop in private key reading if the configured file
cannot be parsed successfully
* driver_madwifi: added support for madwifi-ng
* wpa_gui: do not display password/PSK field contents
* wpa_gui: added CA certificate configuration
* driver_ndis: fixed scan request in ap_scan=2 mode not to change SSID
* driver_ndis: include Beacon IEs in AssocInfo in order to notice if
the new AP is using different WPA/RSN IE
* use longer timeout for IEEE 802.11 association to avoid problems with
drivers that may take more than five second to associate
2005-10-27 - v0.4.6
* allow fallback to WPA, if mixed WPA+WPA2 networks have mismatch in
RSN IE, but WPA IE would match with wpa_supplicant configuration
* added support for named configuration blobs in order to avoid having
to use file system for external files (e.g., certificates);
variables can be set to "blob://<blob name>" instead of file path to
use a named blob; supported fields: pac_file, client_cert,
private_key
* fixed RSN pre-authentication (it was broken in the clean up of WPA
state machine interface in v0.4.5)
* driver_madwifi: set IEEE80211_KEY_GROUP flag for group keys to make
sure the driver configures broadcast decryption correctly
* added ca_path (and ca_path2) configuration variables that can be used
to configure OpenSSL CA path, e.g., /etc/ssl/certs, for using the
system-wide trusted CA list
* added support for starting wpa_supplicant without a configuration
file (-C argument must be used to set ctrl_interface parameter for
this case; in addition, -p argument can be used to provide
driver_param; these new arguments can also be used with a
configuration to override the values from the configuration)
* added global control interface that can be optionally used for adding
and removing network interfaces dynamically (-g command line argument
for both wpa_supplicant and wpa_cli) without having to restart
wpa_supplicant process
* wpa_gui:
- try to save configuration whenever something is modified
- added WEP key configuration
- added possibility to edit the current network configuration
* driver_ndis: fixed driver polling not to increase frequency on each
received EAPOL frame due to incorrectly cancelled timeout
* added simple configuration file examples (in examples subdirectory)
* fixed driver_wext.c to filter wireless events based on ifindex to
avoid interfaces receiving events from other interfaces
* delay sending initial EAPOL-Start couple of seconds to speed up
authentication for the most common case of Authenticator starting
EAP authentication immediately after association
2005-09-25 - v0.4.5
* added a workaround for clearing keys with ndiswrapper to allow
roaming from WPA enabled AP to plaintext one
* added docbook documentation (doc/docbook) that can be used to
generate, e.g., man pages
* l2_packet_linux: use socket type SOCK_DGRAM instead of SOCK_RAW for
PF_PACKET in order to prepare for network devices that do not use
Ethernet headers (e.g., network stack with native IEEE 802.11 frames)
* use receipt of EAPOL-Key frame as a lower layer success indication
for EAP state machine to allow recovery from dropped EAP-Success
frame
* cleaned up internal EAPOL frame processing by not including link
layer (Ethernet) header during WPA and EAPOL/EAP processing; this
header is added only when transmitted the frame; this makes it easier
to use wpa_supplicant on link layers that use different header than
Ethernet
* updated EAP-PSK to use draft 9 by default since this can now be
tested with hostapd; removed support for draft 3, including
server_nai configuration option from network blocks
* driver_wired: add PAE address to the multicast address list in order
to be able to receive EAPOL frames with drivers that do not include
these multicast addresses by default
* driver_wext: add support for WE-19
* added support for multiple configuration backends (CONFIG_BACKEND
option); currently, only 'file' is supported (i.e., the format used
in wpa_supplicant.conf)
* added support for updating configuration ('wpa_cli save_config');
this is disabled by default and can be enabled with global
update_config=1 variable in wpa_supplicant.conf; this allows wpa_cli
and wpa_gui to store the configuration changes in a permanent store
* added GET_NETWORK ctrl_iface command
(e.g., 'wpa_cli get_network 0 ssid')
2005-08-21 - v0.4.4
* replaced OpenSSL patch for EAP-FAST support
(openssl-tls-extensions.patch) with a more generic and correct
patch (the new patch is not compatible with the previous one, so the
OpenSSL library will need to be patched with the new patch in order
to be able to build wpa_supplicant with EAP-FAST support)
* added support for using Windows certificate store (through CryptoAPI)
for client certificate and private key operations (EAP-TLS)
(see wpa_supplicant.conf for more information on how to configure
this with private_key)
* ported wpa_gui to Windows
* added Qt4 version of wpa_gui (wpa_gui-qt4 directory); this can be
built with the open source version of the Qt4 for Windows
* allow non-WPA modes (e.g., IEEE 802.1X with dynamic WEP) to be used
with drivers that do not support WPA
* ndis_events: fixed Windows 2000 support
* added support for enabling/disabling networks from the list of all
configured networks ('wpa_cli enable_network <network id>' and
'wpa_cli disable_network <network id>')
* added support for adding and removing network from the current
configuration ('wpa_cli add_network' and 'wpa_cli remove_network
<network id>'); added networks are disabled by default and they can
be enabled with enable_network command once the configuration is done
for the new network; note: configuration file is not yet updated, so
these new networks are lost when wpa_supplicant is restarted
* added support for setting network configuration parameters through
the control interface, for example:
wpa_cli set_network 0 ssid "\"my network\""
* fixed parsing of strings that include both " and # within double
quoted area (e.g., "start"#end")
* added EAP workaround for PEAP session resumption: allow outer,
i.e., not tunneled, EAP-Success to terminate session since; this can
be disabled with eap_workaround=0
(this was allowed for PEAPv1 before, but now it is also allowed for
PEAPv0 since at least one RADIUS authentication server seems to be
doing this for PEAPv0, too)
* wpa_gui: added preliminary support for adding new networks to the
wpa_supplicant configuration (double click on the scan results to
open network configuration)
2005-06-26 - v0.4.3
* removed interface for external EAPOL/EAP supplicant (e.g.,
Xsupplicant), (CONFIG_XSUPPLICANT_IFACE) since it is not required
anymore and is unlikely to be used by anyone
* driver_ndis: fixed WinPcap 3.0 support
* fixed build with CONFIG_DNET_PCAP=y on Linux
* l2_packet: moved different implementations into separate files
(l2_packet_*.c)
2005-06-12 - v0.4.2
* driver_ipw: updated driver structures to match with ipw2200-1.0.4
(note: ipw2100-1.1.0 is likely to require an update to work with
this)
* added support for using ap_scan=2 mode with multiple network blocks;
wpa_supplicant will go through the networks one by one until the
driver reports a successful association; this uses the same order for
networks as scan_ssid=1 scans, i.e., the priority field is ignored
and the network block order in the file is used instead
* fixed a potential issue in RSN pre-authentication ending up using
freed memory if pre-authentication times out
* added support for matching alternative subject name extensions of the
authentication server certificate; new configuration variables
altsubject_match and altsubject_match2
* driver_ndis: added support for IEEE 802.1X authentication with wired
NDIS drivers
* added support for querying private key password (EAP-TLS) through the
control interface (wpa_cli/wpa_gui) if one is not included in the
configuration file
* driver_broadcom: fixed couple of memory leaks in scan result
processing
* EAP-PAX is now registered as EAP type 46
* fixed EAP-PAX MAC calculation
* fixed EAP-PAX CK and ICK key derivation
* added support for using password with EAP-PAX (as an alternative to
entering key with eappsk); SHA-1 hash of the password will be used as
the key in this case
* added support for arbitrary driver interface parameters through the
configuration file with a new driver_param field; this adds a new
driver_ops function set_param()
* added possibility to override l2_packet module with driver interface
API (new send_eapol handler); this can be used to implement driver
specific TX/RX functions for EAPOL frames
* fixed ctrl_interface_group processing for the case where gid is
entered as a number, not group name
* driver_test: added support for testing hostapd with wpa_supplicant
by using test driver interface without any kernel drivers or network
cards
2005-02-13 - v0.3.8
2005-05-22 - v0.4.1
* driver_madwifi: fixed WPA/WPA2 mode configuration to allow EAPOL
packets to be encrypted; this was apparently broken by the changed
ioctl order in v0.4.0
* driver_madwifi: added preliminary support for compiling against 'BSD'
branch of madwifi CVS tree
* added support for EAP-MSCHAPv2 password retries within the same EAP
authentication session
* added support for password changes with EAP-MSCHAPv2 (used when the
password has expired)
* added support for reading additional certificates from PKCS#12 files
and adding them to the certificate chain
* fixed association with IEEE 802.1X (no WPA) when dynamic WEP keys
were used
* fixed a possible double free in EAP-TTLS fast-reauthentication when
identity or password is entered through control interface
* display EAP Notification messages to user through control interface
with "CTRL-EVENT-EAP-NOTIFICATION" prefix
* added GUI version of wpa_cli, wpa_gui; this is not build
automatically with 'make'; use 'make wpa_gui' to build (this requires
Qt development tools)
* added 'disconnect' command to control interface for setting
wpa_supplicant in state where it will not associate before
'reassociate' command has been used
* added support for selecting a network from the list of all configured
networks ('wpa_cli select_network <network id>'; this disabled all
other networks; to re-enable, 'wpa_cli select_network any')
* added support for getting scan results through control interface
* added EAP workaround for PEAPv1 session resumption: allow outer,
i.e., not tunneled, EAP-Success to terminate session since; this can
be disabled with eap_workaround=0
2005-04-25 - v0.4.0 (beginning of 0.4.x development releases)
* added a new build time option, CONFIG_NO_STDOUT_DEBUG, that can be
used to reduce the size of the wpa_supplicant considerably if
debugging code is not needed
* fixed EAPOL-Key validation to drop packets with invalid Key Data
Length; such frames could have crashed wpa_supplicant due to buffer
overflow
* added support for wired authentication (IEEE 802.1X on wired
Ethernet); driver interface 'wired'
* obsoleted set_wpa() handler in the driver interface API (it can be
replaced by moving enable/disable functionality into init()/deinit())
(calls to set_wpa() are still present for backwards compatibility,
but they may be removed in the future)
* driver_madwifi: fixed association in plaintext mode
* modified the EAP workaround that accepts EAP-Success with incorrect
Identifier to be even less strict about verification in order to
interoperate with some authentication servers
* added support for sending TLS alerts
* added support for 'any' SSID wildcard; if ssid is not configured or
is set to an empty string, any SSID will be accepted for non-WPA AP
* added support for asking PIN (for SIM) from frontends (e.g.,
wpa_cli); if a PIN is needed, but not included in the configuration
file, a control interface request is sent and EAP processing is
delayed until the PIN is available
* added support for using external devices (e.g., a smartcard) for
private key operations in EAP-TLS (CONFIG_SMARTCARD=y in .config);
new wpa_supplicant.conf variables:
- global: opensc_engine_path, pkcs11_engine_path, pkcs11_module_path
- network: engine, engine_id, key_id
* added experimental support for EAP-PAX
* added monitor mode for wpa_cli (-a<path to a program to run>) that
allows external commands (e.g., shell scripts) to be run based on
wpa_supplicant events, e.g., when authentication has been completed
and data connection is ready; other related wpa_cli arguments:
-B (run in background), -P (write PID file); wpa_supplicant has a new
command line argument (-W) that can be used to make it wait until a
control interface command is received in order to avoid missing
events
* added support for opportunistic WPA2 PMKSA key caching (disabled by
default, can be enabled with proactive_key_caching=1)
* fixed RSN IE in 4-Way Handshake message 2/4 for the case where
Authenticator rejects PMKSA caching attempt and the driver is not
using assoc_info events
* added -P<pid file> argument for wpa_supplicant to write the current
process id into a file
2005-02-12 - v0.3.7 (beginning of 0.3.x stable releases)
* added new phase1 option parameter, include_tls_length=1, to force

View file

@ -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 MS_FUNCS
ifndef TLS_FUNCS
LIBS += -lcrypto
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)

View file

@ -1,7 +1,7 @@
WPA Supplicant
==============
Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi> and
Copyright (c) 2003-2006, Jouni Malinen <jkmaline@cc.hut.fi> and
contributors
All Rights Reserved.
@ -89,6 +89,7 @@ Supported WPA/IEEE 802.11i features:
* EAP-SIM
* EAP-AKA
* EAP-PSK
* EAP-PAX
* LEAP (note: requires special support from the driver for IEEE 802.11
authentication)
(following methods are supported, but since they do not generate keying
@ -97,8 +98,6 @@ Supported WPA/IEEE 802.11i features:
* EAP-MSCHAPv2
* EAP-GTC
* EAP-OTP
Alternatively, an external program, e.g., Xsupplicant, can be used for EAP
authentication.
- key management for CCMP, TKIP, WEP104, WEP40
- RSN/WPA2 (IEEE 802.11i)
* pre-authentication
@ -112,6 +111,7 @@ Requirements
Current hardware/software requirements:
- Linux kernel 2.4.x or 2.6.x with Linux Wireless Extensions v15 or newer
- FreeBSD 6-CURRENT
- NetBSD-current
- Microsoft Windows with WinPcap (at least WinXP, may work with other versions)
- drivers:
Host AP driver for Prism2/2.5/3 (development snapshot/v0.2.x)
@ -164,8 +164,10 @@ Current hardware/software requirements:
used with IEEE 802.1X (i.e., not WPA) when using ap_scan=0 option in
configuration file.
Wired Ethernet drivers (with ap_scan=0)
BSD net80211 layer (e.g., Atheros driver)
At the moment, this is for FreeBSD 6-CURRENT branch.
At the moment, this is for FreeBSD 6-CURRENT branch and NetBSD-current.
Windows NDIS
The current Windows port requires WinPcap (http://winpcap.polito.it/).
@ -173,7 +175,8 @@ Current hardware/software requirements:
wpa_supplicant was designed to be portable for different drivers and
operating systems. Hopefully, support for more wlan cards and OSes will be
added in the future. See developer.txt for more information about the
added in the future. See developer's documentation
(http://hostap.epitest.fi/wpa_supplicant/devel/) for more information about the
design of wpa_supplicant and porting to other drivers. One main goal
is to add full WPA/WPA2 support to Linux wireless extensions to allow
new drivers to be supported without having to implement new
@ -221,8 +224,7 @@ networks that require some kind of security. Task group I (Security)
of IEEE 802.11 working group (http://www.ieee802.org/11/) has worked
to address the flaws of the base standard and has in practice
completed its work in May 2004. The IEEE 802.11i amendment to the IEEE
802.11 standard was approved in June 2004 and this amendment is likely
to be published in July 2004.
802.11 standard was approved in June 2004 and published in July 2004.
Wi-Fi Alliance (http://www.wi-fi.org/) used a draft version of the
IEEE 802.11i work (draft 3.0) to define a subset of the security
@ -277,14 +279,6 @@ robust encryption algorithm (CCMP: AES in Counter mode with CBC-MAC)
to replace TKIP and optimizations for handoff (reduced number of
messages in initial key handshake, pre-authentication, and PMKSA caching).
Some wireless LAN vendors are already providing support for CCMP in
their WPA products. There is no "official" interoperability
certification for CCMP and/or mixed modes using both TKIP and CCMP, so
some interoperability issues can be expected even though many
combinations seem to be working with equipment from different vendors.
Certification for WPA2 is likely to start during the second half of
2004.
wpa_supplicant
@ -307,9 +301,9 @@ Following steps are used when associating with an AP using WPA:
- wpa_supplicant selects a BSS based on its configuration
- wpa_supplicant requests the kernel driver to associate with the chosen
BSS
- If WPA-EAP: integrated IEEE 802.1X Supplicant or external Xsupplicant
completes EAP authentication with the authentication server (proxied
by the Authenticator in the AP)
- If WPA-EAP: integrated IEEE 802.1X Supplicant completes EAP
authentication with the authentication server (proxied by the
Authenticator in the AP)
- If WPA-EAP: master key is received from the IEEE 802.1X Supplicant
- If WPA-PSK: wpa_supplicant uses PSK as the master session key
- wpa_supplicant completes WPA 4-Way Handshake and Group Key Handshake
@ -352,6 +346,7 @@ CONFIG_EAP_OTP=y
CONFIG_EAP_SIM=y
CONFIG_EAP_AKA=y
CONFIG_EAP_PSK=y
CONFIG_EAP_PAX=y
CONFIG_EAP_LEAP=y
Following option can be used to include GSM SIM/USIM interface for GSM/UMTS
@ -366,13 +361,12 @@ interface with libpcap/libdnet.
CONFIG_DNET_PCAP=y
Following options can be added to .config to select which driver
interfaces are included. Prism54.org driver is not yet complete and
Hermes driver interface needs to be downloaded from Agere (see above).
Most Linux driver need to include CONFIG_WIRELESS_EXTENSION.
interfaces are included. Hermes driver interface needs to be downloaded
from Agere (see above). CONFIG_WIRELESS_EXTENSION will be used
automatically if any of the selected drivers need it.
CONFIG_WIRELESS_EXTENSION=y
CONFIG_DRIVER_HOSTAP=y
CONFIG_DRIVER_PRISM54=y
CONFIG_DRIVER_HERMES=y
CONFIG_DRIVER_MADWIFI=y
CONFIG_DRIVER_ATMEL=y
@ -387,7 +381,6 @@ Following example includes all features and driver interfaces that are
included in the wpa_supplicant package:
CONFIG_DRIVER_HOSTAP=y
CONFIG_DRIVER_PRISM54=y
CONFIG_DRIVER_HERMES=y
CONFIG_DRIVER_MADWIFI=y
CONFIG_DRIVER_ATMEL=y
@ -409,6 +402,7 @@ CONFIG_EAP_OTP=y
CONFIG_EAP_SIM=y
CONFIG_EAP_AKA=y
CONFIG_EAP_PSK=y
CONFIG_EAP_PAX=y
CONFIG_EAP_LEAP=y
CONFIG_PCSC=y
@ -463,8 +457,6 @@ options:
-d = increase debugging verbosity (-dd even more)
-K = include keys (passwords, etc.) in debug output
-t = include timestamp in debug messages
-e = use external IEEE 802.1X Supplicant (e.g., xsupplicant)
(this disables the internal Supplicant)
-h = show this help text
-L = show license (GPL and BSD)
-q = decrease debugging verbosity (-qq even less)
@ -475,8 +467,6 @@ options:
drivers:
hostap = Host AP driver (Intersil Prism2/2.5/3) [default]
(this can also be used with Linuxant DriverLoader)
prism54 = Prism54.org driver (Intersil Prism GT/Duette/Indigo)
not yet fully implemented
hermes = Agere Systems Inc. driver (Hermes-I/Hermes-II)
madwifi = MADWIFI 802.11 support (Atheros, etc.)
atmel = ATMEL AT76C5XXx (USB, PCMCIA)
@ -484,6 +474,7 @@ drivers:
ndiswrapper = Linux ndiswrapper
broadcom = Broadcom wl.o driver
ipw = Intel ipw2100/2200 driver
wired = wpa_supplicant wired Ethernet driver
bsd = BSD 802.11 support (Atheros, etc.)
ndis = Windows NDIS driver
@ -647,6 +638,21 @@ network={
}
6) Authentication for wired Ethernet. This can be used with 'wired' interface
(-Dwired on command line).
ctrl_interface=/var/run/wpa_supplicant
ctrl_interface_group=wheel
ap_scan=0
network={
key_mgmt=IEEE8021X
eap=MD5
identity="user"
password="password"
eapol_flags=0
}
Certificates
------------
@ -681,7 +687,7 @@ wpa_supplicant. It is used to query current status, change
configuration, trigger events, and request interactive user input.
wpa_cli can show the current authentication status, selected security
mode, dot11 and dot1x MIBs, etc. In addition, it can configuring some
mode, dot11 and dot1x MIBs, etc. In addition, it can configure some
variables like EAPOL state machine parameters and trigger events like
reassociation and IEEE 802.1X logoff/logon. wpa_cli provides a user
interface to request authentication information, like username and
@ -757,11 +763,83 @@ wpa_cli commands
preauthenticate <BSSID> = force preauthentication
identity <network id> <identity> = configure identity for an SSID
password <network id> <password> = configure password for an SSID
pin <network id> <pin> = configure pin for an SSID
otp <network id> <password> = configure one-time-password for an SSID
passphrase <network id> <passphrase> = configure private key passphrase
for an SSID
bssid <network id> <BSSID> = set preferred BSSID for an SSID
list_networks = list configured networks
select_network <network id> = select a network (disable others)
enable_network <network id> = enable a network
disable_network <network id> = disable a network
add_network = add a network
remove_network <network id> = remove a network
set_network <network id> <variable> <value> = set network variables (shows
list of variables when run without arguments)
get_network <network id> <variable> = get network variables
save_config = save the current configuration
disconnect = disconnect and wait for reassociate command before connecting
scan = request new BSS scan
scan_results = get latest scan results
get_capability <eap/pairwise/group/key_mgmt/proto/auth_alg> = get capabilies
terminate = terminate wpa_supplicant
quit = exit wpa_cli
wpa_cli command line options
wpa_cli [-p<path to ctrl sockets>] [-i<ifname>] [-hvB] [-a<action file>] \
[-P<pid file>] [-g<global ctrl>] [command..]
-h = help (show this usage text)
-v = shown version information
-a = run in daemon mode executing the action file based on events from
wpa_supplicant
-B = run a daemon in the background
default path: /var/run/wpa_supplicant
default interface: first interface found in socket path
Using wpa_cli to run external program on connect/disconnect
-----------------------------------------------------------
wpa_cli can used to run external programs whenever wpa_supplicant
connects or disconnects from a network. This can be used, e.g., to
update network configuration and/or trigget DHCP client to update IP
addresses, etc.
One wpa_cli process in "action" mode needs to be started for each
interface. For example, the following command starts wpa_cli for the
default ingterface (-i can be used to select the interface in case of
more than one interface being used at the same time):
wpa_cli -a/sbin/wpa_action.sh -B
The action file (-a option, /sbin/wpa_action.sh in this example) will
be executed whenever wpa_supplicant completes authentication (connect
event) or detects disconnection). The action script will be called
with two command line arguments: interface name and event (CONNECTED
or DISCONNECTED). If the action script needs to get more information
about the current network, it can use 'wpa_cli status' to query
wpa_supplicant for more information.
Following example can be used as a simple template for an action
script:
#!/bin/sh
IFNAME=$1
CMD=$2
if [ "$CMD" == "CONNECTED" ]; then
SSID=`wpa_cli -i$IFNAME status | grep ^ssid= | cut -f2- -d=`
# configure network, signal DHCP client, etc.
fi
if [ "$CMD" == "DISCONNECTED" ]; then
# remove network configuration, if needed
fi
Integrating with pcmcia-cs/cardmgr scripts
------------------------------------------
@ -804,55 +882,38 @@ started--and will then negotiate keys with the AP.
Optional integration with Xsupplicant
-------------------------------------
Dynamic interface add and operation without configuration files
---------------------------------------------------------------
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.
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):
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.
# Start wpa_supplicant in the background
wpa_supplicant -g/var/run/wpa_supplicant-global -B
Example configuration for xsupplicant:
# 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
network_list = all
default_netname = jkm
# 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
jkm
{
type = wireless
allow_types = eap_peap
identity = <BEGIN_ID>jkm<END_ID>
eap-peap {
random_file = /dev/urandom
root_cert = /home/jkm/CA.pem
chunk_size = 1398
allow_types = eap_mschapv2
eap-mschapv2 {
username = <BEGIN_UNAME>jkm<END_UNAME>
password = <BEGIN_PASS>jkm<END_PASS>
}
}
}
# At this point, the new network interface should start trying to associate
# with the WPA-PSK network using SSID test.
Example configuration for wpa_supplicant:
network={
ssid="jkm"
key_mgmt=WPA-EAP
}
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.
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

View file

@ -1,8 +1,15 @@
/*
* AES (Rijndael) cipher
*
* Modifications to public domain implementation:
* - support only 128-bit keys
* - cleanup
* Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
* - use C pre-processor to make it easier to change S table access
* - added option (AES_SMALL_TABLES) for reducing code size by about 8 kB at
* cost of reduced throughput (quite small difference on Pentium 4,
* 10-25% when using -O1 or -O2 optimization)
*
* Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -14,7 +21,7 @@
* See README and COPYING for more details.
*/
/**
/*
* rijndael-alg-fst.c
*
* @version 3.0 (December 2000)
@ -40,7 +47,8 @@
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define FULL_UNROLL
/* #define FULL_UNROLL */
#define AES_SMALL_TABLES
/*
@ -123,6 +131,7 @@ static const u32 Te0[256] = {
0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U,
0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU,
};
#ifndef AES_SMALL_TABLES
static const u32 Te1[256] = {
0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU,
0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U,
@ -388,6 +397,7 @@ static const u32 Te4[256] = {
0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU,
0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U,
};
#endif /* AES_SMALL_TABLES */
static const u32 Td0[256] = {
0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U,
0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U,
@ -454,6 +464,7 @@ static const u32 Td0[256] = {
0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U,
0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U,
};
#ifndef AES_SMALL_TABLES
static const u32 Td1[256] = {
0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU,
0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U,
@ -724,6 +735,116 @@ static const u32 rcon[] = {
0x10000000, 0x20000000, 0x40000000, 0x80000000,
0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
};
#else /* AES_SMALL_TABLES */
static const u8 Td4s[256] = {
0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U,
0xbfU, 0x40U, 0xa3U, 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU,
0x7cU, 0xe3U, 0x39U, 0x82U, 0x9bU, 0x2fU, 0xffU, 0x87U,
0x34U, 0x8eU, 0x43U, 0x44U, 0xc4U, 0xdeU, 0xe9U, 0xcbU,
0x54U, 0x7bU, 0x94U, 0x32U, 0xa6U, 0xc2U, 0x23U, 0x3dU,
0xeeU, 0x4cU, 0x95U, 0x0bU, 0x42U, 0xfaU, 0xc3U, 0x4eU,
0x08U, 0x2eU, 0xa1U, 0x66U, 0x28U, 0xd9U, 0x24U, 0xb2U,
0x76U, 0x5bU, 0xa2U, 0x49U, 0x6dU, 0x8bU, 0xd1U, 0x25U,
0x72U, 0xf8U, 0xf6U, 0x64U, 0x86U, 0x68U, 0x98U, 0x16U,
0xd4U, 0xa4U, 0x5cU, 0xccU, 0x5dU, 0x65U, 0xb6U, 0x92U,
0x6cU, 0x70U, 0x48U, 0x50U, 0xfdU, 0xedU, 0xb9U, 0xdaU,
0x5eU, 0x15U, 0x46U, 0x57U, 0xa7U, 0x8dU, 0x9dU, 0x84U,
0x90U, 0xd8U, 0xabU, 0x00U, 0x8cU, 0xbcU, 0xd3U, 0x0aU,
0xf7U, 0xe4U, 0x58U, 0x05U, 0xb8U, 0xb3U, 0x45U, 0x06U,
0xd0U, 0x2cU, 0x1eU, 0x8fU, 0xcaU, 0x3fU, 0x0fU, 0x02U,
0xc1U, 0xafU, 0xbdU, 0x03U, 0x01U, 0x13U, 0x8aU, 0x6bU,
0x3aU, 0x91U, 0x11U, 0x41U, 0x4fU, 0x67U, 0xdcU, 0xeaU,
0x97U, 0xf2U, 0xcfU, 0xceU, 0xf0U, 0xb4U, 0xe6U, 0x73U,
0x96U, 0xacU, 0x74U, 0x22U, 0xe7U, 0xadU, 0x35U, 0x85U,
0xe2U, 0xf9U, 0x37U, 0xe8U, 0x1cU, 0x75U, 0xdfU, 0x6eU,
0x47U, 0xf1U, 0x1aU, 0x71U, 0x1dU, 0x29U, 0xc5U, 0x89U,
0x6fU, 0xb7U, 0x62U, 0x0eU, 0xaaU, 0x18U, 0xbeU, 0x1bU,
0xfcU, 0x56U, 0x3eU, 0x4bU, 0xc6U, 0xd2U, 0x79U, 0x20U,
0x9aU, 0xdbU, 0xc0U, 0xfeU, 0x78U, 0xcdU, 0x5aU, 0xf4U,
0x1fU, 0xddU, 0xa8U, 0x33U, 0x88U, 0x07U, 0xc7U, 0x31U,
0xb1U, 0x12U, 0x10U, 0x59U, 0x27U, 0x80U, 0xecU, 0x5fU,
0x60U, 0x51U, 0x7fU, 0xa9U, 0x19U, 0xb5U, 0x4aU, 0x0dU,
0x2dU, 0xe5U, 0x7aU, 0x9fU, 0x93U, 0xc9U, 0x9cU, 0xefU,
0xa0U, 0xe0U, 0x3bU, 0x4dU, 0xaeU, 0x2aU, 0xf5U, 0xb0U,
0xc8U, 0xebU, 0xbbU, 0x3cU, 0x83U, 0x53U, 0x99U, 0x61U,
0x17U, 0x2bU, 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U, 0x26U,
0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, 0x21U, 0x0cU, 0x7dU,
};
static const u8 rcons[] = {
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36
/* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
};
#endif /* AES_SMALL_TABLES */
#ifndef AES_SMALL_TABLES
#define RCON(i) rcon[(i)]
#define TE0(i) Te0[((i) >> 24) & 0xff]
#define TE1(i) Te1[((i) >> 16) & 0xff]
#define TE2(i) Te2[((i) >> 8) & 0xff]
#define TE3(i) Te3[(i) & 0xff]
#define TE41(i) (Te4[((i) >> 24) & 0xff] & 0xff000000)
#define TE42(i) (Te4[((i) >> 16) & 0xff] & 0x00ff0000)
#define TE43(i) (Te4[((i) >> 8) & 0xff] & 0x0000ff00)
#define TE44(i) (Te4[(i) & 0xff] & 0x000000ff)
#define TE421(i) (Te4[((i) >> 16) & 0xff] & 0xff000000)
#define TE432(i) (Te4[((i) >> 8) & 0xff] & 0x00ff0000)
#define TE443(i) (Te4[(i) & 0xff] & 0x0000ff00)
#define TE414(i) (Te4[((i) >> 24) & 0xff] & 0x000000ff)
#define TE4(i) (Te4[(i)] & 0x000000ff)
#define TD0(i) Td0[((i) >> 24) & 0xff]
#define TD1(i) Td1[((i) >> 16) & 0xff]
#define TD2(i) Td2[((i) >> 8) & 0xff]
#define TD3(i) Td3[(i) & 0xff]
#define TD41(i) (Td4[((i) >> 24) & 0xff] & 0xff000000)
#define TD42(i) (Td4[((i) >> 16) & 0xff] & 0x00ff0000)
#define TD43(i) (Td4[((i) >> 8) & 0xff] & 0x0000ff00)
#define TD44(i) (Td4[(i) & 0xff] & 0x000000ff)
#define TD0_(i) Td0[(i) & 0xff]
#define TD1_(i) Td1[(i) & 0xff]
#define TD2_(i) Td2[(i) & 0xff]
#define TD3_(i) Td3[(i) & 0xff]
#else /* AES_SMALL_TABLES */
#define RCON(i) (rcons[(i)] << 24)
static inline u32 rotr(u32 val, int bits)
{
return (val >> bits) | (val << (32 - bits));
}
#define TE0(i) Te0[((i) >> 24) & 0xff]
#define TE1(i) rotr(Te0[((i) >> 16) & 0xff], 8)
#define TE2(i) rotr(Te0[((i) >> 8) & 0xff], 16)
#define TE3(i) rotr(Te0[(i) & 0xff], 24)
#define TE41(i) ((Te0[((i) >> 24) & 0xff] << 8) & 0xff000000)
#define TE42(i) (Te0[((i) >> 16) & 0xff] & 0x00ff0000)
#define TE43(i) (Te0[((i) >> 8) & 0xff] & 0x0000ff00)
#define TE44(i) ((Te0[(i) & 0xff] >> 8) & 0x000000ff)
#define TE421(i) ((Te0[((i) >> 16) & 0xff] << 8) & 0xff000000)
#define TE432(i) (Te0[((i) >> 8) & 0xff] & 0x00ff0000)
#define TE443(i) (Te0[(i) & 0xff] & 0x0000ff00)
#define TE414(i) ((Te0[((i) >> 24) & 0xff] >> 8) & 0x000000ff)
#define TE4(i) ((Te0[(i)] >> 8) & 0x000000ff)
#define TD0(i) Td0[((i) >> 24) & 0xff]
#define TD1(i) rotr(Td0[((i) >> 16) & 0xff], 8)
#define TD2(i) rotr(Td0[((i) >> 8) & 0xff], 16)
#define TD3(i) rotr(Td0[(i) & 0xff], 24)
#define TD41(i) (Td4s[((i) >> 24) & 0xff] << 24)
#define TD42(i) (Td4s[((i) >> 16) & 0xff] << 16)
#define TD43(i) (Td4s[((i) >> 8) & 0xff] << 8)
#define TD44(i) (Td4s[(i) & 0xff])
#define TD0_(i) Td0[(i) & 0xff]
#define TD1_(i) rotr(Td0[(i) & 0xff], 8)
#define TD2_(i) rotr(Td0[(i) & 0xff], 16)
#define TD3_(i) rotr(Td0[(i) & 0xff], 24)
#endif /* AES_SMALL_TABLES */
#define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00)
@ -755,11 +876,8 @@ void rijndaelKeySetupEnc(u32 rk[/*44*/], const u8 cipherKey[])
for (i = 0; i < 10; i++) {
temp = rk[3];
rk[4] = rk[0] ^
(Te4[(temp >> 16) & 0xff] & 0xff000000) ^
(Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
(Te4[(temp ) & 0xff] & 0x0000ff00) ^
(Te4[(temp >> 24) ] & 0x000000ff) ^
rcon[i];
TE421(temp) ^ TE432(temp) ^ TE443(temp) ^ TE414(temp) ^
RCON(i);
rk[5] = rk[1] ^ rk[4];
rk[6] = rk[2] ^ rk[5];
rk[7] = rk[3] ^ rk[6];
@ -790,33 +908,19 @@ void rijndaelKeySetupDec(u32 rk[/*44*/], const u8 cipherKey[])
* first and the last: */
for (i = 1; i < Nr; i++) {
rk += 4;
rk[0] =
Td0[Te4[(rk[0] >> 24) ] & 0xff] ^
Td1[Te4[(rk[0] >> 16) & 0xff] & 0xff] ^
Td2[Te4[(rk[0] >> 8) & 0xff] & 0xff] ^
Td3[Te4[(rk[0] ) & 0xff] & 0xff];
rk[1] =
Td0[Te4[(rk[1] >> 24) ] & 0xff] ^
Td1[Te4[(rk[1] >> 16) & 0xff] & 0xff] ^
Td2[Te4[(rk[1] >> 8) & 0xff] & 0xff] ^
Td3[Te4[(rk[1] ) & 0xff] & 0xff];
rk[2] =
Td0[Te4[(rk[2] >> 24) ] & 0xff] ^
Td1[Te4[(rk[2] >> 16) & 0xff] & 0xff] ^
Td2[Te4[(rk[2] >> 8) & 0xff] & 0xff] ^
Td3[Te4[(rk[2] ) & 0xff] & 0xff];
rk[3] =
Td0[Te4[(rk[3] >> 24) ] & 0xff] ^
Td1[Te4[(rk[3] >> 16) & 0xff] & 0xff] ^
Td2[Te4[(rk[3] >> 8) & 0xff] & 0xff] ^
Td3[Te4[(rk[3] ) & 0xff] & 0xff];
for (j = 0; j < 4; j++) {
rk[j] = TD0_(TE4((rk[j] >> 24) )) ^
TD1_(TE4((rk[j] >> 16) & 0xff)) ^
TD2_(TE4((rk[j] >> 8) & 0xff)) ^
TD3_(TE4((rk[j] ) & 0xff));
}
}
}
void rijndaelEncrypt(const u32 rk[/*44*/], const u8 pt[16], u8 ct[16])
{
u32 s0, s1, s2, s3, t0, t1, t2, t3;
int Nr = 10;
const int Nr = 10;
#ifndef FULL_UNROLL
int r;
#endif /* ?FULL_UNROLL */
@ -829,153 +933,61 @@ void rijndaelEncrypt(const u32 rk[/*44*/], const u8 pt[16], u8 ct[16])
s1 = GETU32(pt + 4) ^ rk[1];
s2 = GETU32(pt + 8) ^ rk[2];
s3 = GETU32(pt + 12) ^ rk[3];
#define ROUND(i,d,s) \
d##0 = TE0(s##0) ^ TE1(s##1) ^ TE2(s##2) ^ TE3(s##3) ^ rk[4 * i]; \
d##1 = TE0(s##1) ^ TE1(s##2) ^ TE2(s##3) ^ TE3(s##0) ^ rk[4 * i + 1]; \
d##2 = TE0(s##2) ^ TE1(s##3) ^ TE2(s##0) ^ TE3(s##1) ^ rk[4 * i + 2]; \
d##3 = TE0(s##3) ^ TE1(s##0) ^ TE2(s##1) ^ TE3(s##2) ^ rk[4 * i + 3]
#ifdef FULL_UNROLL
/* round 1: */
t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4];
t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5];
t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6];
t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7];
/* round 2: */
s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8];
s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9];
s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10];
s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11];
/* round 3: */
t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12];
t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13];
t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14];
t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15];
/* round 4: */
s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[16];
s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[17];
s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[18];
s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[19];
/* round 5: */
t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[20];
t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[21];
t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[22];
t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[23];
/* round 6: */
s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[24];
s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[25];
s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[26];
s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[27];
/* round 7: */
t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[28];
t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[29];
t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[30];
t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[31];
/* round 8: */
s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[32];
s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[33];
s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[34];
s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[35];
/* round 9: */
t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[36];
t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37];
t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38];
t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39];
rk += Nr << 2;
ROUND(1,t,s);
ROUND(2,s,t);
ROUND(3,t,s);
ROUND(4,s,t);
ROUND(5,t,s);
ROUND(6,s,t);
ROUND(7,t,s);
ROUND(8,s,t);
ROUND(9,t,s);
rk += Nr << 2;
#else /* !FULL_UNROLL */
/*
* Nr - 1 full rounds:
*/
r = Nr >> 1;
for (;;) {
t0 =
Te0[(s0 >> 24) ] ^
Te1[(s1 >> 16) & 0xff] ^
Te2[(s2 >> 8) & 0xff] ^
Te3[(s3 ) & 0xff] ^
rk[4];
t1 =
Te0[(s1 >> 24) ] ^
Te1[(s2 >> 16) & 0xff] ^
Te2[(s3 >> 8) & 0xff] ^
Te3[(s0 ) & 0xff] ^
rk[5];
t2 =
Te0[(s2 >> 24) ] ^
Te1[(s3 >> 16) & 0xff] ^
Te2[(s0 >> 8) & 0xff] ^
Te3[(s1 ) & 0xff] ^
rk[6];
t3 =
Te0[(s3 >> 24) ] ^
Te1[(s0 >> 16) & 0xff] ^
Te2[(s1 >> 8) & 0xff] ^
Te3[(s2 ) & 0xff] ^
rk[7];
rk += 8;
if (--r == 0) {
break;
}
/* Nr - 1 full rounds: */
r = Nr >> 1;
for (;;) {
ROUND(1,t,s);
rk += 8;
if (--r == 0)
break;
ROUND(0,s,t);
}
s0 =
Te0[(t0 >> 24) ] ^
Te1[(t1 >> 16) & 0xff] ^
Te2[(t2 >> 8) & 0xff] ^
Te3[(t3 ) & 0xff] ^
rk[0];
s1 =
Te0[(t1 >> 24) ] ^
Te1[(t2 >> 16) & 0xff] ^
Te2[(t3 >> 8) & 0xff] ^
Te3[(t0 ) & 0xff] ^
rk[1];
s2 =
Te0[(t2 >> 24) ] ^
Te1[(t3 >> 16) & 0xff] ^
Te2[(t0 >> 8) & 0xff] ^
Te3[(t1 ) & 0xff] ^
rk[2];
s3 =
Te0[(t3 >> 24) ] ^
Te1[(t0 >> 16) & 0xff] ^
Te2[(t1 >> 8) & 0xff] ^
Te3[(t2 ) & 0xff] ^
rk[3];
}
#endif /* ?FULL_UNROLL */
/*
#undef ROUND
/*
* apply last round and
* map cipher state to byte array block:
*/
s0 =
(Te4[(t0 >> 24) ] & 0xff000000) ^
(Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
(Te4[(t2 >> 8) & 0xff] & 0x0000ff00) ^
(Te4[(t3 ) & 0xff] & 0x000000ff) ^
rk[0];
s0 = TE41(t0) ^ TE42(t1) ^ TE43(t2) ^ TE44(t3) ^ rk[0];
PUTU32(ct , s0);
s1 =
(Te4[(t1 >> 24) ] & 0xff000000) ^
(Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
(Te4[(t3 >> 8) & 0xff] & 0x0000ff00) ^
(Te4[(t0 ) & 0xff] & 0x000000ff) ^
rk[1];
s1 = TE41(t1) ^ TE42(t2) ^ TE43(t3) ^ TE44(t0) ^ rk[1];
PUTU32(ct + 4, s1);
s2 =
(Te4[(t2 >> 24) ] & 0xff000000) ^
(Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
(Te4[(t0 >> 8) & 0xff] & 0x0000ff00) ^
(Te4[(t1 ) & 0xff] & 0x000000ff) ^
rk[2];
s2 = TE41(t2) ^ TE42(t3) ^ TE43(t0) ^ TE44(t1) ^ rk[2];
PUTU32(ct + 8, s2);
s3 =
(Te4[(t3 >> 24) ] & 0xff000000) ^
(Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
(Te4[(t1 >> 8) & 0xff] & 0x0000ff00) ^
(Te4[(t2 ) & 0xff] & 0x000000ff) ^
rk[3];
s3 = TE41(t3) ^ TE42(t0) ^ TE43(t1) ^ TE44(t2) ^ rk[3];
PUTU32(ct + 12, s3);
}
void rijndaelDecrypt(const u32 rk[/*44*/], const u8 ct[16], u8 pt[16])
{
u32 s0, s1, s2, s3, t0, t1, t2, t3;
int Nr = 10;
const int Nr = 10;
#ifndef FULL_UNROLL
int r;
#endif /* ?FULL_UNROLL */
@ -984,149 +996,110 @@ void rijndaelDecrypt(const u32 rk[/*44*/], const u8 ct[16], u8 pt[16])
* map byte array block to cipher state
* and add initial round key:
*/
s0 = GETU32(ct ) ^ rk[0];
s1 = GETU32(ct + 4) ^ rk[1];
s2 = GETU32(ct + 8) ^ rk[2];
s3 = GETU32(ct + 12) ^ rk[3];
s0 = GETU32(ct ) ^ rk[0];
s1 = GETU32(ct + 4) ^ rk[1];
s2 = GETU32(ct + 8) ^ rk[2];
s3 = GETU32(ct + 12) ^ rk[3];
#define ROUND(i,d,s) \
d##0 = TD0(s##0) ^ TD1(s##3) ^ TD2(s##2) ^ TD3(s##1) ^ rk[4 * i]; \
d##1 = TD0(s##1) ^ TD1(s##0) ^ TD2(s##3) ^ TD3(s##2) ^ rk[4 * i + 1]; \
d##2 = TD0(s##2) ^ TD1(s##1) ^ TD2(s##0) ^ TD3(s##3) ^ rk[4 * i + 2]; \
d##3 = TD0(s##3) ^ TD1(s##2) ^ TD2(s##1) ^ TD3(s##0) ^ rk[4 * i + 3]
#ifdef FULL_UNROLL
/* round 1: */
t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[ 4];
t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[ 5];
t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[ 6];
t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[ 7];
/* round 2: */
s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[ 8];
s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[ 9];
s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[10];
s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[11];
/* round 3: */
t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[12];
t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[13];
t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[14];
t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[15];
/* round 4: */
s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[16];
s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[17];
s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[18];
s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[19];
/* round 5: */
t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[20];
t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[21];
t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[22];
t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[23];
/* round 6: */
s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[24];
s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[25];
s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[26];
s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[27];
/* round 7: */
t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[28];
t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[29];
t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[30];
t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[31];
/* round 8: */
s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[32];
s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[33];
s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[34];
s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[35];
/* round 9: */
t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[36];
t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[37];
t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[38];
t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[39];
ROUND(1,t,s);
ROUND(2,s,t);
ROUND(3,t,s);
ROUND(4,s,t);
ROUND(5,t,s);
ROUND(6,s,t);
ROUND(7,t,s);
ROUND(8,s,t);
ROUND(9,t,s);
rk += Nr << 2;
#else /* !FULL_UNROLL */
/*
* Nr - 1 full rounds:
*/
r = Nr >> 1;
for (;;) {
t0 =
Td0[(s0 >> 24) ] ^
Td1[(s3 >> 16) & 0xff] ^
Td2[(s2 >> 8) & 0xff] ^
Td3[(s1 ) & 0xff] ^
rk[4];
t1 =
Td0[(s1 >> 24) ] ^
Td1[(s0 >> 16) & 0xff] ^
Td2[(s3 >> 8) & 0xff] ^
Td3[(s2 ) & 0xff] ^
rk[5];
t2 =
Td0[(s2 >> 24) ] ^
Td1[(s1 >> 16) & 0xff] ^
Td2[(s0 >> 8) & 0xff] ^
Td3[(s3 ) & 0xff] ^
rk[6];
t3 =
Td0[(s3 >> 24) ] ^
Td1[(s2 >> 16) & 0xff] ^
Td2[(s1 >> 8) & 0xff] ^
Td3[(s0 ) & 0xff] ^
rk[7];
rk += 8;
if (--r == 0) {
break;
}
/* Nr - 1 full rounds: */
r = Nr >> 1;
for (;;) {
ROUND(1,t,s);
rk += 8;
if (--r == 0)
break;
ROUND(0,s,t);
}
s0 =
Td0[(t0 >> 24) ] ^
Td1[(t3 >> 16) & 0xff] ^
Td2[(t2 >> 8) & 0xff] ^
Td3[(t1 ) & 0xff] ^
rk[0];
s1 =
Td0[(t1 >> 24) ] ^
Td1[(t0 >> 16) & 0xff] ^
Td2[(t3 >> 8) & 0xff] ^
Td3[(t2 ) & 0xff] ^
rk[1];
s2 =
Td0[(t2 >> 24) ] ^
Td1[(t1 >> 16) & 0xff] ^
Td2[(t0 >> 8) & 0xff] ^
Td3[(t3 ) & 0xff] ^
rk[2];
s3 =
Td0[(t3 >> 24) ] ^
Td1[(t2 >> 16) & 0xff] ^
Td2[(t1 >> 8) & 0xff] ^
Td3[(t0 ) & 0xff] ^
rk[3];
}
#endif /* ?FULL_UNROLL */
/*
#undef ROUND
/*
* apply last round and
* map cipher state to byte array block:
*/
s0 =
(Td4[(t0 >> 24) ] & 0xff000000) ^
(Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
(Td4[(t2 >> 8) & 0xff] & 0x0000ff00) ^
(Td4[(t1 ) & 0xff] & 0x000000ff) ^
rk[0];
s0 = TD41(t0) ^ TD42(t3) ^ TD43(t2) ^ TD44(t1) ^ rk[0];
PUTU32(pt , s0);
s1 =
(Td4[(t1 >> 24) ] & 0xff000000) ^
(Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
(Td4[(t3 >> 8) & 0xff] & 0x0000ff00) ^
(Td4[(t2 ) & 0xff] & 0x000000ff) ^
rk[1];
s1 = TD41(t1) ^ TD42(t0) ^ TD43(t3) ^ TD44(t2) ^ rk[1];
PUTU32(pt + 4, s1);
s2 =
(Td4[(t2 >> 24) ] & 0xff000000) ^
(Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
(Td4[(t0 >> 8) & 0xff] & 0x0000ff00) ^
(Td4[(t3 ) & 0xff] & 0x000000ff) ^
rk[2];
s2 = TD41(t2) ^ TD42(t1) ^ TD43(t0) ^ TD44(t3) ^ rk[2];
PUTU32(pt + 8, s2);
s3 =
(Td4[(t3 >> 24) ] & 0xff000000) ^
(Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
(Td4[(t1 >> 8) & 0xff] & 0x0000ff00) ^
(Td4[(t0 ) & 0xff] & 0x000000ff) ^
rk[3];
s3 = TD41(t3) ^ TD42(t2) ^ TD43(t1) ^ TD44(t0) ^ rk[3];
PUTU32(pt + 12, s3);
}
/* Generic wrapper functions for AES functions */
void * aes_encrypt_init(const u8 *key, size_t len)
{
u32 *rk;
if (len != 16)
return NULL;
rk = malloc(4 * 44);
if (rk == NULL)
return NULL;
rijndaelKeySetupEnc(rk, key);
return rk;
}
void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
{
rijndaelEncrypt(ctx, plain, crypt);
}
void aes_encrypt_deinit(void *ctx)
{
free(ctx);
}
void * aes_decrypt_init(const u8 *key, size_t len)
{
u32 *rk;
if (len != 16)
return NULL;
rk = malloc(4 * 44);
if (rk == NULL)
return NULL;
rijndaelKeySetupDec(rk, key);
return rk;
}
void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
{
rijndaelDecrypt(ctx, crypt, plain);
}
void aes_decrypt_deinit(void *ctx)
{
free(ctx);
}

View file

@ -1,10 +1,13 @@
/*
* AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
* One-Key CBC MAC (OMAC1) hash with AES-128
* AES-128 CTR mode encryption
* AES-128 EAX mode encryption/decryption
* AES-128 CBC
* Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
* AES-based functions
*
* - AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
* - One-Key CBC MAC (OMAC1) hash with AES-128
* - AES-128 CTR mode encryption
* - AES-128 EAX mode encryption/decryption
* - AES-128 CBC
*
* Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -21,43 +24,26 @@
#include <string.h>
#include "common.h"
#include "aes_wrap.h"
#include "crypto.h"
#ifdef EAP_TLS_FUNCS
#include <openssl/aes.h>
#else /* EAP_TLS_FUNCS */
#ifndef EAP_TLS_FUNCS
#include "aes.c"
struct aes_key_st {
u32 rk[44];
};
typedef struct aes_key_st AES_KEY;
#define AES_set_encrypt_key(userKey, bits, key) \
rijndaelKeySetupEnc((key)->rk, (userKey))
#define AES_set_decrypt_key(userKey, bits, key) \
rijndaelKeySetupDec((key)->rk, (userKey))
#define AES_encrypt(in, out, key) \
rijndaelEncrypt((key)->rk, in, out)
#define AES_decrypt(in, out, key) \
rijndaelDecrypt((key)->rk, in, out)
#endif /* EAP_TLS_FUNCS */
/*
* @kek: key encryption key (KEK)
* @n: length of the wrapped key in 64-bit units; e.g., 2 = 128-bit = 16 bytes
* @plain: plaintext key to be wrapped, n * 64 bit
* @cipher: wrapped key, (n + 1) * 64 bit
/**
* aes_wrap - Wrap keys with AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
* @kek: Key encryption key (KEK)
* @n: Length of the wrapped key in 64-bit units; e.g., 2 = 128-bit = 16 bytes
* @plain: Plaintext key to be wrapped, n * 64 bit
* @cipher: Wrapped key, (n + 1) * 64 bit
* Returns: 0 on success, -1 on failure
*/
void aes_wrap(u8 *kek, int n, u8 *plain, u8 *cipher)
int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher)
{
u8 *a, *r, b[16];
int i, j;
AES_KEY key;
void *ctx;
a = cipher;
r = cipher + 8;
@ -66,7 +52,9 @@ void aes_wrap(u8 *kek, int n, u8 *plain, u8 *cipher)
memset(a, 0xa6, 8);
memcpy(r, plain, 8 * n);
AES_set_encrypt_key(kek, 128, &key);
ctx = aes_encrypt_init(kek, 16);
if (ctx == NULL)
return -1;
/* 2) Calculate intermediate values.
* For j = 0 to 5
@ -80,40 +68,47 @@ void aes_wrap(u8 *kek, int n, u8 *plain, u8 *cipher)
for (i = 1; i <= n; i++) {
memcpy(b, a, 8);
memcpy(b + 8, r, 8);
AES_encrypt(b, b, &key);
aes_encrypt(ctx, b, b);
memcpy(a, b, 8);
a[7] ^= n * j + i;
memcpy(r, b + 8, 8);
r += 8;
}
}
aes_encrypt_deinit(ctx);
/* 3) Output the results.
*
* These are already in @cipher due to the location of temporary
* variables.
*/
return 0;
}
/*
* @kek: key encryption key (KEK)
* @n: length of the wrapped key in 64-bit units; e.g., 2 = 128-bit = 16 bytes
* @cipher: wrapped key to be unwrapped, (n + 1) * 64 bit
* @plain: plaintext key, n * 64 bit
/**
* aes_unwrap - Unwrap key with AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
* @kek: Key encryption key (KEK)
* @n: Length of the wrapped key in 64-bit units; e.g., 2 = 128-bit = 16 bytes
* @cipher: Wrapped key to be unwrapped, (n + 1) * 64 bit
* @plain: Plaintext key, n * 64 bit
* Returns: 0 on success, -1 on failure (e.g., integrity verification failed)
*/
int aes_unwrap(u8 *kek, int n, u8 *cipher, u8 *plain)
int aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain)
{
u8 a[8], *r, b[16];
int i, j;
AES_KEY key;
void *ctx;
/* 1) Initialize variables. */
memcpy(a, cipher, 8);
r = plain;
memcpy(r, cipher + 8, 8 * n);
AES_set_decrypt_key(kek, 128, &key);
ctx = aes_decrypt_init(kek, 16);
if (ctx == NULL)
return -1;
/* 2) Compute intermediate values.
* For j = 5 to 0
@ -129,12 +124,13 @@ int aes_unwrap(u8 *kek, int n, u8 *cipher, u8 *plain)
b[7] ^= n * j + i;
memcpy(b + 8, r, 8);
AES_decrypt(b, b, &key);
aes_decrypt(ctx, b, b);
memcpy(a, b, 8);
memcpy(r, b + 8, 8);
r -= 8;
}
}
aes_decrypt_deinit(ctx);
/* 3) Output results.
*
@ -165,27 +161,37 @@ static void gf_mulx(u8 *pad)
}
void omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
/**
* omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128
* @key: Key for the hash operation
* @data: Data buffer for which a MAC is determined
* @data: Length of data buffer in bytes
* @mac: Buffer for MAC (128 bits, i.e., 16 bytes)
* Returns: 0 on success, -1 on failure
*/
int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
{
AES_KEY akey;
void *ctx;
u8 cbc[BLOCK_SIZE], pad[BLOCK_SIZE];
const u8 *pos = data;
int i;
size_t left = data_len;
AES_set_encrypt_key(key, 128, &akey);
ctx = aes_encrypt_init(key, 16);
if (ctx == NULL)
return -1;
memset(cbc, 0, BLOCK_SIZE);
while (left >= BLOCK_SIZE) {
for (i = 0; i < BLOCK_SIZE; i++)
cbc[i] ^= *pos++;
if (left > BLOCK_SIZE)
AES_encrypt(cbc, cbc, &akey);
aes_encrypt(ctx, cbc, cbc);
left -= BLOCK_SIZE;
}
memset(pad, 0, BLOCK_SIZE);
AES_encrypt(pad, pad, &akey);
aes_encrypt(ctx, pad, pad);
gf_mulx(pad);
if (left || data_len == 0) {
@ -197,32 +203,55 @@ void omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
for (i = 0; i < BLOCK_SIZE; i++)
pad[i] ^= cbc[i];
AES_encrypt(pad, mac, &akey);
aes_encrypt(ctx, pad, mac);
aes_encrypt_deinit(ctx);
return 0;
}
void aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out)
/**
* aes_128_encrypt_block - Perform one AES 128-bit block operation
* @key: Key for AES
* @in: Input data (16 bytes)
* @out: Output of the AES block operation (16 bytes)
* Returns: 0 on success, -1 on failure
*/
int aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out)
{
AES_KEY akey;
AES_set_encrypt_key(key, 128, &akey);
AES_encrypt(in, out, &akey);
void *ctx;
ctx = aes_encrypt_init(key, 16);
if (ctx == NULL)
return -1;
aes_encrypt(ctx, in, out);
aes_encrypt_deinit(ctx);
return 0;
}
void aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
u8 *data, size_t data_len)
/**
* aes_128_ctr_encrypt - AES-128 CTR mode encryption
* @key: Key for encryption (16 bytes)
* @nonce: Nonce for counter mode (16 bytes)
* @data: Data to encrypt in-place
* @data_len: Length of data in bytes
* Returns: 0 on success, -1 on failure
*/
int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
u8 *data, size_t data_len)
{
AES_KEY akey;
void *ctx;
size_t len, left = data_len;
int i;
u8 *pos = data;
u8 counter[BLOCK_SIZE], buf[BLOCK_SIZE];
AES_set_encrypt_key(key, 128, &akey);
ctx = aes_encrypt_init(key, 16);
if (ctx == NULL)
return -1;
memcpy(counter, nonce, BLOCK_SIZE);
while (left > 0) {
AES_encrypt(counter, buf, &akey);
aes_encrypt(ctx, counter, buf);
len = (left < BLOCK_SIZE) ? left : BLOCK_SIZE;
for (i = 0; i < len; i++)
@ -236,9 +265,23 @@ void aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
break;
}
}
aes_encrypt_deinit(ctx);
return 0;
}
/**
* aes_128_eax_encrypt - AES-128 EAX mode encryption
* @key: Key for encryption (16 bytes)
* @nonce: Nonce for counter mode
* @nonce_len: Nonce length in bytes
* @hdr: Header data to be authenticity protected
* @hdr_len: Length of the header data bytes
* @data: Data to encrypt in-place
* @data_len: Length of data in bytes
* @tag: 16-byte tag value
* Returns: 0 on success, -1 on failure
*/
int aes_128_eax_encrypt(const u8 *key, const u8 *nonce, size_t nonce_len,
const u8 *hdr, size_t hdr_len,
u8 *data, size_t data_len, u8 *tag)
@ -284,6 +327,18 @@ int aes_128_eax_encrypt(const u8 *key, const u8 *nonce, size_t nonce_len,
}
/**
* aes_128_eax_decrypt - AES-128 EAX mode decryption
* @key: Key for decryption (16 bytes)
* @nonce: Nonce for counter mode
* @nonce_len: Nonce length in bytes
* @hdr: Header data to be authenticity protected
* @hdr_len: Length of the header data bytes
* @data: Data to encrypt in-place
* @data_len: Length of data in bytes
* @tag: 16-byte tag value
* Returns: 0 on success, -1 on failure, -2 if tag does not match
*/
int aes_128_eax_decrypt(const u8 *key, const u8 *nonce, size_t nonce_len,
const u8 *hdr, size_t hdr_len,
u8 *data, size_t data_len, const u8 *tag)
@ -332,48 +387,70 @@ int aes_128_eax_decrypt(const u8 *key, const u8 *nonce, size_t nonce_len,
}
void aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data,
size_t data_len)
/**
* aes_128_cbc_encrypt - AES-128 CBC encryption
* @key: Encryption key
* @iv: Encryption IV for CBC mode (16 bytes)
* @data: Data to encrypt in-place
* @data_len: Length of data in bytes (must be divisible by 16)
* Returns: 0 on success, -1 on failure
*/
int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
{
AES_KEY akey;
void *ctx;
u8 cbc[BLOCK_SIZE];
u8 *pos = data;
int i, j, blocks;
AES_set_encrypt_key(key, 128, &akey);
ctx = aes_encrypt_init(key, 16);
if (ctx == NULL)
return -1;
memcpy(cbc, iv, BLOCK_SIZE);
blocks = data_len / BLOCK_SIZE;
for (i = 0; i < blocks; i++) {
for (j = 0; j < BLOCK_SIZE; j++)
cbc[j] ^= pos[j];
AES_encrypt(cbc, cbc, &akey);
aes_encrypt(ctx, cbc, cbc);
memcpy(pos, cbc, BLOCK_SIZE);
pos += BLOCK_SIZE;
}
aes_encrypt_deinit(ctx);
return 0;
}
void aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data,
size_t data_len)
/**
* aes_128_cbc_decrypt - AES-128 CBC decryption
* @key: Decryption key
* @iv: Decryption IV for CBC mode (16 bytes)
* @data: Data to decrypt in-place
* @data_len: Length of data in bytes (must be divisible by 16)
* Returns: 0 on success, -1 on failure
*/
int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
{
AES_KEY akey;
void *ctx;
u8 cbc[BLOCK_SIZE], tmp[BLOCK_SIZE];
u8 *pos = data;
int i, j, blocks;
AES_set_decrypt_key(key, 128, &akey);
ctx = aes_decrypt_init(key, 16);
if (ctx == NULL)
return -1;
memcpy(cbc, iv, BLOCK_SIZE);
blocks = data_len / BLOCK_SIZE;
for (i = 0; i < blocks; i++) {
memcpy(tmp, pos, BLOCK_SIZE);
AES_decrypt(pos, pos, &akey);
aes_decrypt(ctx, pos, pos);
for (j = 0; j < BLOCK_SIZE; j++)
pos[j] ^= cbc[j];
memcpy(cbc, tmp, BLOCK_SIZE);
pos += BLOCK_SIZE;
}
aes_decrypt_deinit(ctx);
return 0;
}
@ -388,25 +465,28 @@ static void test_aes_perf(void)
const int num_iters = 10;
int i;
unsigned int start, end;
AES_KEY akey;
u8 key[16], pt[16], ct[16];
void *ctx;
printf("keySetupEnc:");
for (i = 0; i < num_iters; i++) {
rdtscll(start);
AES_set_encrypt_key(key, 128, &akey);
ctx = aes_encrypt_init(key, 16);
rdtscll(end);
aes_encrypt_deinit(ctx);
printf(" %d", end - start);
}
printf("\n");
printf("Encrypt:");
ctx = aes_encrypt_init(key, 16);
for (i = 0; i < num_iters; i++) {
rdtscll(start);
AES_encrypt(pt, ct, &akey);
aes_encrypt(ctx, pt, ct);
rdtscll(end);
printf(" %d", end - start);
}
aes_encrypt_deinit(ctx);
printf("\n");
}
#endif /* __i386__ */
@ -599,7 +679,10 @@ int main(int argc, char *argv[])
int ret = 0, i;
struct omac1_test_vector *tv;
aes_wrap(kek, 2, plain, result);
if (aes_wrap(kek, 2, plain, result)) {
printf("AES-WRAP-128-128 reported failure\n");
ret++;
}
if (memcmp(result, crypt, 24) != 0) {
printf("AES-WRAP-128-128 failed\n");
ret++;

View file

@ -1,21 +1,42 @@
/*
* AES-based functions
*
* - AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
* - One-Key CBC MAC (OMAC1) hash with AES-128
* - AES-128 CTR mode encryption
* - AES-128 EAX mode encryption/decryption
* - AES-128 CBC
*
* Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef AES_WRAP_H
#define AES_WRAP_H
void aes_wrap(u8 *kek, int n, u8 *plain, u8 *cipher);
int aes_unwrap(u8 *kek, int n, u8 *cipher, u8 *plain);
void omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac);
void aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out);
void aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
u8 *data, size_t data_len);
int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher);
int aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain);
int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac);
int aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out);
int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
u8 *data, size_t data_len);
int aes_128_eax_encrypt(const u8 *key, const u8 *nonce, size_t nonce_len,
const u8 *hdr, size_t hdr_len,
u8 *data, size_t data_len, u8 *tag);
int aes_128_eax_decrypt(const u8 *key, const u8 *nonce, size_t nonce_len,
const u8 *hdr, size_t hdr_len,
u8 *data, size_t data_len, const u8 *tag);
void aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data,
size_t data_len);
void aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data,
size_t data_len);
int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data,
size_t data_len);
int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data,
size_t data_len);
#endif /* AES_WRAP_H */

View file

@ -0,0 +1,198 @@
/*
* Base64 encoding/decoding (RFC1341)
* Copyright (c) 2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include <stdlib.h>
#include <string.h>
#include "base64.h"
static const unsigned char base64_table[64] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/**
* base64_encode - Base64 encode
* @src: Data to be encoded
* @len: Length of the data to be encoded
* @out_len: Pointer to output length variable, or %NULL if not used
* Returns: Allocated buffer of out_len bytes of encoded data,
* or %NULL on failure
*
* Caller is responsible for freeing the returned buffer. Returned buffer is
* nul terminated to make it easier to use as a C string. The nul terminator is
* not included in out_len.
*/
unsigned char * base64_encode(const unsigned char *src, size_t len,
size_t *out_len)
{
unsigned char *out, *pos;
const unsigned char *end, *in;
size_t olen;
int line_len;
olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */
olen += olen / 72; /* line feeds */
olen++; /* nul termination */
out = malloc(olen);
if (out == NULL)
return NULL;
end = src + len;
in = src;
pos = out;
line_len = 0;
while (end - in >= 3) {
*pos++ = base64_table[in[0] >> 2];
*pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)];
*pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)];
*pos++ = base64_table[in[2] & 0x3f];
in += 3;
line_len += 4;
if (line_len >= 72) {
*pos++ = '\n';
line_len = 0;
}
}
if (end - in) {
*pos++ = base64_table[in[0] >> 2];
if (end - in == 1) {
*pos++ = base64_table[(in[0] & 0x03) << 4];
*pos++ = '=';
} else {
*pos++ = base64_table[((in[0] & 0x03) << 4) |
(in[1] >> 4)];
*pos++ = base64_table[(in[1] & 0x0f) << 2];
}
*pos++ = '=';
line_len += 4;
}
if (line_len)
*pos++ = '\n';
*pos = '\0';
if (out_len)
*out_len = pos - out;
return out;
}
/**
* base64_decode - Base64 decode
* @src: Data to be decoded
* @len: Length of the data to be decoded
* @out_len: Pointer to output length variable
* Returns: Allocated buffer of out_len bytes of decoded data,
* or %NULL on failure
*
* Caller is responsible for freeing the returned buffer.
*/
unsigned char * base64_decode(const unsigned char *src, size_t len,
size_t *out_len)
{
unsigned char dtable[256], *out, *pos, in[4], block[4], tmp;
size_t i, count, olen;
memset(dtable, 0x80, 256);
for (i = 0; i < sizeof(base64_table); i++)
dtable[base64_table[i]] = i;
dtable['='] = 0;
count = 0;
for (i = 0; i < len; i++) {
if (dtable[src[i]] != 0x80)
count++;
}
if (count % 4)
return NULL;
olen = count / 4 * 3;
pos = out = malloc(count);
if (out == NULL)
return NULL;
count = 0;
for (i = 0; i < len; i++) {
tmp = dtable[src[i]];
if (tmp == 0x80)
continue;
in[count] = src[i];
block[count] = tmp;
count++;
if (count == 4) {
*pos++ = (block[0] << 2) | (block[1] >> 4);
*pos++ = (block[1] << 4) | (block[2] >> 2);
*pos++ = (block[2] << 6) | block[3];
count = 0;
}
}
if (pos > out) {
if (in[2] == '=')
pos -= 2;
else if (in[3] == '=')
pos--;
}
*out_len = pos - out;
return out;
}
#ifdef TEST_MAIN
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *f;
size_t len, elen;
unsigned char *buf, *e;
if (argc != 4) {
printf("Usage: base64 <encode|decode> <in file> <out file>\n");
return -1;
}
f = fopen(argv[2], "r");
if (f == NULL)
return -1;
fseek(f, 0, SEEK_END);
len = ftell(f);
fseek(f, 0, SEEK_SET);
buf = malloc(len);
if (buf == NULL) {
fclose(f);
return -1;
}
fread(buf, 1, len, f);
fclose(f);
if (strcmp(argv[1], "encode") == 0)
e = base64_encode(buf, len, &elen);
else
e = base64_decode(buf, len, &elen);
if (e == NULL)
return -2;
f = fopen(argv[3], "w");
if (f == NULL)
return -3;
fwrite(e, 1, elen, f);
fclose(f);
free(e);
return 0;
}
#endif /* TEST_MAIN */

View file

@ -0,0 +1,23 @@
/*
* Base64 encoding/decoding (RFC1341)
* Copyright (c) 2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef BASE64_H
#define BASE64_h
unsigned char * base64_encode(const unsigned char *src, size_t len,
size_t *out_len);
unsigned char * base64_decode(const unsigned char *src, size_t len,
size_t *out_len);
#endif /* BASE64_H */

View file

@ -1,6 +1,5 @@
/*
* Host AP (software wireless LAN access point) user space daemon for
* Host AP kernel driver / common helper functions, etc.
* wpa_supplicant/hostapd / common helper functions, etc.
* Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
@ -22,6 +21,10 @@
#include <ctype.h>
#include <time.h>
#include <sys/time.h>
#ifdef CONFIG_NATIVE_WINDOWS
#include <winsock2.h>
#include <wincrypt.h>
#endif /* CONFIG_NATIVE_WINDOWS */
#include "common.h"
@ -34,12 +37,17 @@ int wpa_debug_timestamp = 0;
int hostapd_get_rand(u8 *buf, size_t len)
{
#ifdef CONFIG_NATIVE_WINDOWS
int i;
/* FIX: use more secure pseudo random number generator */
for (i = 0; i < len; i++) {
buf[i] = rand();
}
return 0;
HCRYPTPROV prov;
BOOL ret;
if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT))
return -1;
ret = CryptGenRandom(prov, len, buf);
CryptReleaseContext(prov, 0);
return ret ? 0 : -1;
#else /* CONFIG_NATIVE_WINDOWS */
FILE *f;
size_t rc;
@ -93,6 +101,12 @@ static int hex2byte(const char *hex)
}
/**
* hwaddr_aton - Convert ASCII string to MAC address
* @txt: MAC address as a string (e.g., "00:11:22:33:44:55")
* @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
* Returns: 0 on success, -1 on failure (e.g., string not a MAC address)
*/
int hwaddr_aton(const char *txt, u8 *addr)
{
int i;
@ -115,6 +129,14 @@ int hwaddr_aton(const char *txt, u8 *addr)
}
/**
* hexstr2bin - Convert ASCII hex string into binary data
* @hex: ASCII hex string (e.g., "01ab")
* @buf: Buffer for the binary data
* @len: Length of the text to convert in bytes (of buf); hex will be double
* this size
* Returns: 0 on success, -1 on failure (invalid hex string)
*/
int hexstr2bin(const char *hex, u8 *buf, size_t len)
{
int i, a;
@ -171,6 +193,15 @@ char * rel2abs_path(const char *rel_path)
}
/**
* inc_byte_array - Increment arbitrary length byte array by one
* @counter: Pointer to byte array
* @len: Length of the counter in bytes
*
* This function increments the last byte of the counter by one and continues
* rolling over to more significant bytes if the byte was incremented from
* 0xff to 0x00.
*/
void inc_byte_array(u8 *counter, size_t len)
{
int pos = len - 1;
@ -201,7 +232,9 @@ void fprint_char(FILE *f, char c)
}
static void wpa_debug_print_timestamp(void)
#ifndef CONFIG_NO_STDOUT_DEBUG
void wpa_debug_print_timestamp(void)
{
struct timeval tv;
char buf[16];
@ -218,6 +251,17 @@ static void wpa_debug_print_timestamp(void)
}
/**
* wpa_printf - conditional printf
* @level: priority level (MSG_*) of the message
* @fmt: printf format string, followed by optional arguments
*
* This function is used to print conditional debugging and error messages. The
* output may be directed to stdout, stderr, and/or syslog based on
* configuration.
*
* Note: New line '\n' is added to the end of the text when printing to stdout.
*/
void wpa_printf(int level, char *fmt, ...)
{
va_list ap;
@ -240,7 +284,9 @@ static void _wpa_hexdump(int level, const char *title, const u8 *buf,
return;
wpa_debug_print_timestamp();
printf("%s - hexdump(len=%lu):", title, (unsigned long) len);
if (show) {
if (buf == NULL) {
printf(" [NULL]");
} else if (show) {
for (i = 0; i < len; i++)
printf(" %02x", buf[i]);
} else {
@ -276,6 +322,11 @@ static void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
title, (unsigned long) len);
return;
}
if (buf == NULL) {
printf("%s - hexdump_ascii(len=%lu): [NULL]\n",
title, (unsigned long) len);
return;
}
printf("%s - hexdump_ascii(len=%lu):\n", title, (unsigned long) len);
while (len) {
llen = len > line_len ? line_len : len;
@ -312,6 +363,8 @@ void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
_wpa_hexdump_ascii(level, title, buf, len, wpa_debug_show_keys);
}
#endif /* CONFIG_NO_STDOUT_DEBUG */
#ifdef CONFIG_NATIVE_WINDOWS

View file

@ -1,11 +1,26 @@
/*
* wpa_supplicant/hostapd / common helper functions, etc.
* Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef COMMON_H
#define COMMON_H
#ifdef __linux__
#include <endian.h>
#include <byteswap.h>
#endif
#ifdef __FreeBSD__
#endif /* __linux__ */
#if defined(__FreeBSD__) || defined(__NetBSD__)
#include <sys/types.h>
#include <sys/endian.h>
#define __BYTE_ORDER _BYTE_ORDER
@ -14,10 +29,9 @@
#define bswap_16 bswap16
#define bswap_32 bswap32
#define bswap_64 bswap64
#endif
#endif /* defined(__FreeBSD__) || defined(__NetBSD__) */
#ifdef CONFIG_NATIVE_WINDOWS
#include <winsock.h>
#include <winsock2.h>
static inline int daemon(int nochdir, int noclose)
@ -54,6 +68,18 @@ struct timezone {
int gettimeofday(struct timeval *tv, struct timezone *tz);
static inline long int random(void)
{
return rand();
}
typedef int gid_t;
typedef int socklen_t;
#ifndef MSG_DONTWAIT
#define MSG_DONTWAIT 0 /* not supported */
#endif
#endif /* CONFIG_NATIVE_WINDOWS */
#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS)
@ -104,6 +130,21 @@ static inline unsigned int wpa_swap_32(unsigned int v)
#endif /* __CYGWIN__ */
/* Macros for handling unaligned 16-bit variables */
#define WPA_GET_BE16(a) ((u16) (((a)[0] << 8) | (a)[1]))
#define WPA_PUT_BE16(a, val) \
do { \
(a)[0] = ((u16) (val)) >> 8; \
(a)[1] = ((u16) (val)) & 0xff; \
} while (0)
#define WPA_GET_LE16(a) ((u16) (((a)[1] << 8) | (a)[0]))
#define WPA_PUT_LE16(a, val) \
do { \
(a)[1] = ((u16) (val)) >> 8; \
(a)[0] = ((u16) (val)) & 0xff; \
} while (0)
#ifndef ETH_ALEN
#define ETH_ALEN 6
@ -134,6 +175,26 @@ void fprint_char(FILE *f, char c);
enum { MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR };
#ifdef CONFIG_NO_STDOUT_DEBUG
#define wpa_debug_print_timestamp() do { } while (0)
#define wpa_printf(args...) do { } while (0)
#define wpa_hexdump(args...) do { } while (0)
#define wpa_hexdump_key(args...) do { } while (0)
#define wpa_hexdump_ascii(args...) do { } while (0)
#define wpa_hexdump_ascii_key(args...) do { } while (0)
#else /* CONFIG_NO_STDOUT_DEBUG */
/**
* wpa_debug_printf_timestamp - Print timestamp for debug output
*
* This function prints a timestamp in <seconds from 1970>.<microsoconds>
* format if debug output has been configured to include timestamps in debug
* messages.
*/
void wpa_debug_print_timestamp(void);
/**
* wpa_printf - conditional printf
* @level: priority level (MSG_*) of the message
@ -153,11 +214,11 @@ __attribute__ ((format (printf, 2, 3)));
* @level: priority level (MSG_*) of the message
* @title: title of for the message
* @buf: data buffer to be dumped
* @len: length of the @buf
* @len: length of the buf
*
* This function is used to print conditional debugging and error messages. The
* output may be directed to stdout, stderr, and/or syslog based on
* configuration. The contents of @buf is printed out has hex dump.
* configuration. The contents of buf is printed out has hex dump.
*/
void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len);
@ -166,11 +227,11 @@ void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len);
* @level: priority level (MSG_*) of the message
* @title: title of for the message
* @buf: data buffer to be dumped
* @len: length of the @buf
* @len: length of the buf
*
* This function is used to print conditional debugging and error messages. The
* output may be directed to stdout, stderr, and/or syslog based on
* configuration. The contents of @buf is printed out has hex dump. This works
* configuration. The contents of buf is printed out has hex dump. This works
* like wpa_hexdump(), but by default, does not include secret keys (passwords,
* etc.) in debug output.
*/
@ -181,11 +242,11 @@ void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len);
* @level: priority level (MSG_*) of the message
* @title: title of for the message
* @buf: data buffer to be dumped
* @len: length of the @buf
* @len: length of the buf
*
* This function is used to print conditional debugging and error messages. The
* output may be directed to stdout, stderr, and/or syslog based on
* configuration. The contents of @buf is printed out has hex dump with both
* configuration. The contents of buf is printed out has hex dump with both
* the hex numbers and ASCII characters (for printable range) are shown. 16
* bytes per line will be shown.
*/
@ -197,11 +258,11 @@ void wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
* @level: priority level (MSG_*) of the message
* @title: title of for the message
* @buf: data buffer to be dumped
* @len: length of the @buf
* @len: length of the buf
*
* This function is used to print conditional debugging and error messages. The
* output may be directed to stdout, stderr, and/or syslog based on
* configuration. The contents of @buf is printed out has hex dump with both
* configuration. The contents of buf is printed out has hex dump with both
* the hex numbers and ASCII characters (for printable range) are shown. 16
* bytes per line will be shown. This works like wpa_hexdump_ascii(), but by
* default, does not include secret keys (passwords, etc.) in debug output.
@ -209,6 +270,9 @@ void wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
size_t len);
#endif /* CONFIG_NO_STDOUT_DEBUG */
#ifdef EAPOL_TEST
#define WPA_ASSERT(a) \
do { \

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,17 @@
/*
* WPA Supplicant / Configuration file structures
* Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef CONFIG_H
#define CONFIG_H
@ -7,27 +21,297 @@
#endif /* CONFIG_CTRL_IFACE_UDP */
#endif /* CONFIG_CTRL_IFACE */
#define DEFAULT_EAPOL_VERSION 1
#define DEFAULT_AP_SCAN 1
#define DEFAULT_FAST_REAUTH 1
#include "config_ssid.h"
struct wpa_config {
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 */
int eapol_version;
int ap_scan;
char *ctrl_interface; /* directory for UNIX domain sockets */
#ifdef CONFIG_CTRL_IFACE
#ifndef CONFIG_CTRL_IFACE_UDP
gid_t ctrl_interface_gid;
#endif /* CONFIG_CTRL_IFACE_UDP */
int ctrl_interface_gid_set;
#endif /* CONFIG_CTRL_IFACE */
int fast_reauth;
/**
* 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_config_read(const char *config_file);
/**
* 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 {
/**
* 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;
/**
* 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;
};
/* 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 */

View file

@ -0,0 +1,695 @@
/*
* WPA Supplicant / Configuration backend: text file
* Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*
* This file implements a configuration backend for text files. All the
* configuration information is stored in a text file that uses a format
* described in the sample configuration file, wpa_supplicant.conf.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "common.h"
#include "wpa.h"
#include "wpa_supplicant.h"
#include "config.h"
#include "base64.h"
static char * wpa_config_get_line(char *s, int size, FILE *stream, int *line)
{
char *pos, *end, *sstart;
while (fgets(s, size, stream)) {
(*line)++;
s[size - 1] = '\0';
pos = s;
while (*pos == ' ' || *pos == '\t' || *pos == '\r')
pos++;
if (*pos == '#' || *pos == '\n' || *pos == '\0' ||
*pos == '\r')
continue;
/* Remove # comments unless they are within a double quoted
* string. Remove trailing white space. */
sstart = strchr(pos, '"');
if (sstart)
sstart = strrchr(sstart + 1, '"');
if (!sstart)
sstart = pos;
end = strchr(sstart, '#');
if (end)
*end-- = '\0';
else
end = pos + strlen(pos) - 1;
while (end > pos &&
(*end == '\n' || *end == ' ' || *end == '\t' ||
*end == '\r')) {
*end-- = '\0';
}
if (*pos == '\0')
continue;
return pos;
}
return NULL;
}
static struct wpa_ssid * wpa_config_read_network(FILE *f, int *line, int id)
{
struct wpa_ssid *ssid;
int errors = 0, end = 0;
char buf[256], *pos, *pos2;
wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new network block",
*line);
ssid = (struct wpa_ssid *) malloc(sizeof(*ssid));
if (ssid == NULL)
return NULL;
memset(ssid, 0, sizeof(*ssid));
ssid->id = id;
wpa_config_set_network_defaults(ssid);
while ((pos = wpa_config_get_line(buf, sizeof(buf), f, line))) {
if (strcmp(pos, "}") == 0) {
end = 1;
break;
}
pos2 = strchr(pos, '=');
if (pos2 == NULL) {
wpa_printf(MSG_ERROR, "Line %d: Invalid SSID line "
"'%s'.", *line, pos);
errors++;
continue;
}
*pos2++ = '\0';
if (*pos2 == '"') {
if (strchr(pos2 + 1, '"') == NULL) {
wpa_printf(MSG_ERROR, "Line %d: invalid "
"quotation '%s'.", *line, pos2);
errors++;
continue;
}
}
if (wpa_config_set(ssid, pos, pos2, *line) < 0)
errors++;
}
if (!end) {
wpa_printf(MSG_ERROR, "Line %d: network block was not "
"terminated properly.", *line);
errors++;
}
if (ssid->passphrase) {
if (ssid->psk_set) {
wpa_printf(MSG_ERROR, "Line %d: both PSK and "
"passphrase configured.", *line);
errors++;
}
wpa_config_update_psk(ssid);
}
if ((ssid->key_mgmt & WPA_KEY_MGMT_PSK) && !ssid->psk_set) {
wpa_printf(MSG_ERROR, "Line %d: WPA-PSK accepted for key "
"management, but no PSK configured.", *line);
errors++;
}
if ((ssid->group_cipher & WPA_CIPHER_CCMP) &&
!(ssid->pairwise_cipher & WPA_CIPHER_CCMP)) {
/* Group cipher cannot be stronger than the pairwise cipher. */
wpa_printf(MSG_DEBUG, "Line %d: removed CCMP from group cipher"
" list since it was not allowed for pairwise "
"cipher", *line);
ssid->group_cipher &= ~WPA_CIPHER_CCMP;
}
if (errors) {
free(ssid);
ssid = NULL;
}
return ssid;
}
static struct wpa_config_blob * wpa_config_read_blob(FILE *f, int *line,
const char *name)
{
struct wpa_config_blob *blob;
char buf[256], *pos;
unsigned char *encoded = NULL, *nencoded;
int end = 0;
size_t encoded_len = 0, len;
wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new named blob '%s'",
*line, name);
while ((pos = wpa_config_get_line(buf, sizeof(buf), f, line))) {
if (strcmp(pos, "}") == 0) {
end = 1;
break;
}
len = strlen(pos);
nencoded = realloc(encoded, encoded_len + len);
if (nencoded == NULL) {
wpa_printf(MSG_ERROR, "Line %d: not enough memory for "
"blob", *line);
free(encoded);
return NULL;
}
encoded = nencoded;
memcpy(encoded + encoded_len, pos, len);
encoded_len += len;
}
if (!end) {
wpa_printf(MSG_ERROR, "Line %d: blob was not terminated "
"properly", *line);
free(encoded);
return NULL;
}
blob = malloc(sizeof(*blob));
if (blob == NULL) {
free(encoded);
return NULL;
}
memset(blob, 0, sizeof(*blob));
blob->name = strdup(name);
blob->data = base64_decode(encoded, encoded_len, &blob->len);
free(encoded);
if (blob->name == NULL || blob->data == NULL) {
wpa_config_free_blob(blob);
return NULL;
}
return blob;
}
struct wpa_config * wpa_config_read(const char *name)
{
FILE *f;
char buf[256], *pos;
int errors = 0, line = 0;
struct wpa_ssid *ssid, *tail = NULL, *head = NULL;
struct wpa_config *config;
int id = 0, prio;
config = wpa_config_alloc_empty(NULL, NULL);
if (config == NULL)
return NULL;
wpa_printf(MSG_DEBUG, "Reading configuration file '%s'", name);
f = fopen(name, "r");
if (f == NULL) {
free(config);
return NULL;
}
while ((pos = wpa_config_get_line(buf, sizeof(buf), f, &line))) {
if (strcmp(pos, "network={") == 0) {
ssid = wpa_config_read_network(f, &line, id++);
if (ssid == NULL) {
wpa_printf(MSG_ERROR, "Line %d: failed to "
"parse network block.", line);
errors++;
continue;
}
if (head == NULL) {
head = tail = ssid;
} else {
tail->next = ssid;
tail = ssid;
}
if (wpa_config_add_prio_network(config, ssid)) {
wpa_printf(MSG_ERROR, "Line %d: failed to add "
"network block to priority list.",
line);
errors++;
continue;
}
} else if (strncmp(pos, "blob-base64-", 12) == 0) {
char *name = pos + 12, *name_end;
struct wpa_config_blob *blob;
name_end = strchr(name, '=');
if (name_end == NULL) {
wpa_printf(MSG_ERROR, "Line %d: no blob name "
"terminator", line);
errors++;
continue;
}
*name_end = '\0';
blob = wpa_config_read_blob(f, &line, name);
if (blob == NULL) {
wpa_printf(MSG_ERROR, "Line %d: failed to read"
" blob %s", line, name);
errors++;
continue;
}
wpa_config_set_blob(config, blob);
#ifdef CONFIG_CTRL_IFACE
} else if (strncmp(pos, "ctrl_interface=", 15) == 0) {
free(config->ctrl_interface);
config->ctrl_interface = strdup(pos + 15);
wpa_printf(MSG_DEBUG, "ctrl_interface='%s'",
config->ctrl_interface);
#ifndef CONFIG_CTRL_IFACE_UDP
} else if (strncmp(pos, "ctrl_interface_group=", 21) == 0) {
struct group *grp;
char *endp;
const char *group = pos + 21;
grp = getgrnam(group);
if (grp) {
config->ctrl_interface_gid = grp->gr_gid;
config->ctrl_interface_gid_set = 1;
wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
" (from group name '%s')",
(int) config->ctrl_interface_gid,
group);
continue;
}
/* Group name not found - try to parse this as gid */
config->ctrl_interface_gid = strtol(group, &endp, 10);
if (*group == '\0' || *endp != '\0') {
wpa_printf(MSG_DEBUG, "Line %d: Invalid group "
"'%s'", line, group);
errors++;
continue;
}
config->ctrl_interface_gid_set = 1;
wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
(int) config->ctrl_interface_gid);
#endif /* CONFIG_CTRL_IFACE_UDP */
#endif /* CONFIG_CTRL_IFACE */
} else if (strncmp(pos, "eapol_version=", 14) == 0) {
config->eapol_version = atoi(pos + 14);
if (config->eapol_version < 1 ||
config->eapol_version > 2) {
wpa_printf(MSG_ERROR, "Line %d: Invalid EAPOL "
"version (%d): '%s'.",
line, config->eapol_version, pos);
errors++;
continue;
}
wpa_printf(MSG_DEBUG, "eapol_version=%d",
config->eapol_version);
} else if (strncmp(pos, "ap_scan=", 8) == 0) {
config->ap_scan = atoi(pos + 8);
wpa_printf(MSG_DEBUG, "ap_scan=%d", config->ap_scan);
} else if (strncmp(pos, "fast_reauth=", 12) == 0) {
config->fast_reauth = atoi(pos + 12);
wpa_printf(MSG_DEBUG, "fast_reauth=%d",
config->fast_reauth);
} else if (strncmp(pos, "opensc_engine_path=", 19) == 0) {
free(config->opensc_engine_path);
config->opensc_engine_path = strdup(pos + 19);
wpa_printf(MSG_DEBUG, "opensc_engine_path='%s'",
config->opensc_engine_path);
} else if (strncmp(pos, "pkcs11_engine_path=", 19) == 0) {
free(config->pkcs11_engine_path);
config->pkcs11_engine_path = strdup(pos + 19);
wpa_printf(MSG_DEBUG, "pkcs11_engine_path='%s'",
config->pkcs11_engine_path);
} else if (strncmp(pos, "pkcs11_module_path=", 19) == 0) {
free(config->pkcs11_module_path);
config->pkcs11_module_path = strdup(pos + 19);
wpa_printf(MSG_DEBUG, "pkcs11_module_path='%s'",
config->pkcs11_module_path);
} else if (strncmp(pos, "driver_param=", 13) == 0) {
free(config->driver_param);
config->driver_param = strdup(pos + 13);
wpa_printf(MSG_DEBUG, "driver_param='%s'",
config->driver_param);
} else if (strncmp(pos, "dot11RSNAConfigPMKLifetime=", 27) ==
0) {
config->dot11RSNAConfigPMKLifetime = atoi(pos + 27);
wpa_printf(MSG_DEBUG, "dot11RSNAConfigPMKLifetime=%d",
config->dot11RSNAConfigPMKLifetime);
} else if (strncmp(pos, "dot11RSNAConfigPMKReauthThreshold=",
34) ==
0) {
config->dot11RSNAConfigPMKReauthThreshold =
atoi(pos + 34);
wpa_printf(MSG_DEBUG,
"dot11RSNAConfigPMKReauthThreshold=%d",
config->dot11RSNAConfigPMKReauthThreshold);
} else if (strncmp(pos, "dot11RSNAConfigSATimeout=", 25) ==
0) {
config->dot11RSNAConfigSATimeout = atoi(pos + 25);
wpa_printf(MSG_DEBUG, "dot11RSNAConfigSATimeout=%d",
config->dot11RSNAConfigSATimeout);
} else if (strncmp(pos, "update_config=", 14) == 0) {
config->update_config = atoi(pos + 14);
wpa_printf(MSG_DEBUG, "update_config=%d",
config->update_config);
} else {
wpa_printf(MSG_ERROR, "Line %d: Invalid configuration "
"line '%s'.", line, pos);
errors++;
continue;
}
}
fclose(f);
config->ssid = head;
for (prio = 0; prio < config->num_prio; prio++) {
ssid = config->pssid[prio];
wpa_printf(MSG_DEBUG, "Priority group %d",
ssid->priority);
while (ssid) {
wpa_printf(MSG_DEBUG, " id=%d ssid='%s'",
ssid->id,
wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
ssid = ssid->pnext;
}
}
if (errors) {
wpa_config_free(config);
config = NULL;
head = NULL;
}
return config;
}
static void write_str(FILE *f, const char *field, struct wpa_ssid *ssid)
{
char *value = wpa_config_get(ssid, field);
if (value == NULL)
return;
fprintf(f, "\t%s=%s\n", field, value);
free(value);
}
static void write_int(FILE *f, const char *field, int value, int def)
{
if (value == def)
return;
fprintf(f, "\t%s=%d\n", field, value);
}
static void write_bssid(FILE *f, struct wpa_ssid *ssid)
{
char *value = wpa_config_get(ssid, "bssid");
if (value == NULL)
return;
fprintf(f, "\tbssid=%s\n", value);
free(value);
}
static void write_psk(FILE *f, struct wpa_ssid *ssid)
{
char *value = wpa_config_get(ssid, "psk");
if (value == NULL)
return;
fprintf(f, "\tpsk=%s\n", value);
free(value);
}
static void write_proto(FILE *f, struct wpa_ssid *ssid)
{
char *value;
if (ssid->proto == DEFAULT_PROTO)
return;
value = wpa_config_get(ssid, "proto");
if (value == NULL)
return;
if (value[0])
fprintf(f, "\tproto=%s\n", value);
free(value);
}
static void write_key_mgmt(FILE *f, struct wpa_ssid *ssid)
{
char *value;
if (ssid->key_mgmt == DEFAULT_KEY_MGMT)
return;
value = wpa_config_get(ssid, "key_mgmt");
if (value == NULL)
return;
if (value[0])
fprintf(f, "\tkey_mgmt=%s\n", value);
free(value);
}
static void write_pairwise(FILE *f, struct wpa_ssid *ssid)
{
char *value;
if (ssid->pairwise_cipher == DEFAULT_PAIRWISE)
return;
value = wpa_config_get(ssid, "pairwise");
if (value == NULL)
return;
if (value[0])
fprintf(f, "\tpairwise=%s\n", value);
free(value);
}
static void write_group(FILE *f, struct wpa_ssid *ssid)
{
char *value;
if (ssid->group_cipher == DEFAULT_GROUP)
return;
value = wpa_config_get(ssid, "group");
if (value == NULL)
return;
if (value[0])
fprintf(f, "\tgroup=%s\n", value);
free(value);
}
static void write_auth_alg(FILE *f, struct wpa_ssid *ssid)
{
char *value;
if (ssid->auth_alg == 0)
return;
value = wpa_config_get(ssid, "auth_alg");
if (value == NULL)
return;
if (value[0])
fprintf(f, "\tauth_alg=%s\n", value);
free(value);
}
static void write_eap(FILE *f, struct wpa_ssid *ssid)
{
char *value;
value = wpa_config_get(ssid, "eap");
if (value == NULL)
return;
if (value[0])
fprintf(f, "\teap=%s\n", value);
free(value);
}
static void write_wep_key(FILE *f, int idx, struct wpa_ssid *ssid)
{
char field[20], *value;
snprintf(field, sizeof(field), "wep_key%d", idx);
value = wpa_config_get(ssid, field);
if (value) {
fprintf(f, "\t%s=%s\n", field, value);
free(value);
}
}
static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
{
int i;
#define STR(t) write_str(f, #t, ssid)
#define INT(t) write_int(f, #t, ssid->t, 0)
#define INT_DEF(t, def) write_int(f, #t, ssid->t, def)
STR(ssid);
INT(scan_ssid);
write_bssid(f, ssid);
write_psk(f, ssid);
write_proto(f, ssid);
write_key_mgmt(f, ssid);
write_pairwise(f, ssid);
write_group(f, ssid);
write_auth_alg(f, ssid);
write_eap(f, ssid);
STR(identity);
STR(anonymous_identity);
STR(eappsk);
STR(nai);
STR(password);
STR(ca_cert);
STR(client_cert);
STR(private_key);
STR(private_key_passwd);
STR(dh_file);
STR(subject_match);
STR(altsubject_match);
STR(ca_cert2);
STR(client_cert2);
STR(private_key2);
STR(private_key2_passwd);
STR(dh_file2);
STR(subject_match2);
STR(altsubject_match2);
STR(phase1);
STR(phase2);
STR(pcsc);
STR(pin);
STR(engine_id);
STR(key_id);
INT(engine);
INT_DEF(eapol_flags, DEFAULT_EAPOL_FLAGS);
for (i = 0; i < 4; i++)
write_wep_key(f, i, ssid);
INT(wep_tx_keyidx);
INT(priority);
INT_DEF(eap_workaround, DEFAULT_EAP_WORKAROUND);
STR(pac_file);
INT(mode);
INT(proactive_key_caching);
INT(disabled);
#undef STR
#undef INT
#undef INT_DEF
}
static int wpa_config_write_blob(FILE *f, struct wpa_config_blob *blob)
{
unsigned char *encoded;
encoded = base64_encode(blob->data, blob->len, NULL);
if (encoded == NULL)
return -1;
fprintf(f, "\nblob-base64-%s={\n%s}\n", blob->name, encoded);
free(encoded);
return 0;
}
int wpa_config_write(const char *name, struct wpa_config *config)
{
FILE *f;
struct wpa_ssid *ssid;
struct wpa_config_blob *blob;
int ret = 0;
wpa_printf(MSG_DEBUG, "Writing configuration file '%s'", name);
f = fopen(name, "w");
if (f == NULL) {
wpa_printf(MSG_DEBUG, "Failed to open '%s' for writing", name);
return -1;
}
#ifdef CONFIG_CTRL_IFACE
if (config->ctrl_interface)
fprintf(f, "ctrl_interface=%s\n", config->ctrl_interface);
#ifndef CONFIG_CTRL_IFACE_UDP
if (config->ctrl_interface_gid_set) {
fprintf(f, "ctrl_interface_group=%d\n",
(int) config->ctrl_interface_gid);
}
#endif /* CONFIG_CTRL_IFACE_UDP */
#endif /* CONFIG_CTRL_IFACE */
if (config->eapol_version != DEFAULT_EAPOL_VERSION)
fprintf(f, "eapol_version=%d\n", config->eapol_version);
if (config->ap_scan != DEFAULT_AP_SCAN)
fprintf(f, "ap_scan=%d\n", config->ap_scan);
if (config->fast_reauth != DEFAULT_FAST_REAUTH)
fprintf(f, "fast_reauth=%d\n", config->fast_reauth);
if (config->opensc_engine_path)
fprintf(f, "opensc_engine_path=%s\n",
config->opensc_engine_path);
if (config->pkcs11_engine_path)
fprintf(f, "pkcs11_engine_path=%s\n",
config->pkcs11_engine_path);
if (config->pkcs11_module_path)
fprintf(f, "pkcs11_module_path=%s\n",
config->pkcs11_module_path);
if (config->driver_param)
fprintf(f, "driver_param=%s\n", config->driver_param);
if (config->dot11RSNAConfigPMKLifetime)
fprintf(f, "dot11RSNAConfigPMKLifetime=%d\n",
config->dot11RSNAConfigPMKLifetime);
if (config->dot11RSNAConfigPMKReauthThreshold)
fprintf(f, "dot11RSNAConfigPMKReauthThreshold=%d\n",
config->dot11RSNAConfigPMKReauthThreshold);
if (config->dot11RSNAConfigSATimeout)
fprintf(f, "dot11RSNAConfigSATimeout=%d\n",
config->dot11RSNAConfigSATimeout);
if (config->update_config)
fprintf(f, "update_config=%d\n", config->update_config);
for (ssid = config->ssid; ssid; ssid = ssid->next) {
fprintf(f, "\nnetwork={\n");
wpa_config_write_network(f, ssid);
fprintf(f, "}\n");
}
for (blob = config->blobs; blob; blob = blob->next) {
ret = wpa_config_write_blob(f, blob);
if (ret)
break;
}
fclose(f);
wpa_printf(MSG_DEBUG, "Configuration file '%s' written %ssuccessfully",
name, ret ? "un" : "");
return ret;
}

View file

@ -1,3 +1,17 @@
/*
* WPA Supplicant / Network configuration structures
* Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef CONFIG_SSID_H
#define CONFIG_SSID_H
@ -24,86 +38,731 @@
#define PMK_LEN 32
#define EAP_PSK_LEN 16
#define DEFAULT_EAP_WORKAROUND ((unsigned int) -1)
#define DEFAULT_EAPOL_FLAGS (EAPOL_FLAG_REQUIRE_KEY_UNICAST | \
EAPOL_FLAG_REQUIRE_KEY_BROADCAST)
#define DEFAULT_PROTO (WPA_PROTO_WPA | WPA_PROTO_RSN)
#define DEFAULT_KEY_MGMT (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X)
#define DEFAULT_PAIRWISE (WPA_CIPHER_CCMP | WPA_CIPHER_TKIP)
#define DEFAULT_GROUP (WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | \
WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)
/**
* struct wpa_ssid - Network configuration data
*
* This structure includes all the configuration variables for a network. This
* data is included in the per-interface configuration data as an element of
* the network list, struct wpa_config::ssid. Each network block in the
* configuration is mapped to a struct wpa_ssid instance.
*/
struct wpa_ssid {
struct wpa_ssid *next; /* next network in global list */
struct wpa_ssid *pnext; /* next network in per-priority list */
int id; /* unique id for ctrl_iface */
/**
* next - Next network in global list
*
* This pointer can be used to iterate over all networks. The head of
* this list is stored in the ssid field of struct wpa_config.
*/
struct wpa_ssid *next;
/**
* pnext - Next network in per-priority list
*
* This pointer can be used to iterate over all networks in the same
* priority class. The heads of these list are stored in the pssid
* fields of struct wpa_config.
*/
struct wpa_ssid *pnext;
/**
* id - Unique id for the network
*
* This identifier is used as a unique identifier for each network
* block when using the control interface. Each network is allocated an
* id when it is being created, either when reading the configuration
* file or when a new network is added through the control interface.
*/
int id;
/**
* priority - Priority group
*
* By default, all networks will get same priority group (0). If some
* of the networks are more desirable, this field can be used to change
* the order in which wpa_supplicant goes through the networks when
* selecting a BSS. The priority groups will be iterated in decreasing
* priority (i.e., the larger the priority value, the sooner the
* network is matched against the scan results). Within each priority
* group, networks will be selected based on security policy, signal
* strength, etc.
*
* Please note that AP scanning with scan_ssid=1 and ap_scan=2 mode are
* not using this priority to select the order for scanning. Instead,
* they try the networks in the order that used in the configuration
* file.
*/
int priority;
/**
* ssid - Service set identifier (network name)
*
* This is the SSID for the network. For wireless interfaces, this is
* used to select which network will be used. If set to %NULL (or
* ssid_len=0), any SSID can be used. For wired interfaces, this must
* be set to %NULL. Note: SSID may contain any characters, even nul
* (ASCII 0) and as such, this should not be assumed to be a nul
* terminated string. ssid_len defines how many characters are valid
* and the ssid field is not guaranteed to be nul terminated.
*/
u8 *ssid;
/**
* ssid_len - Length of the SSID
*/
size_t ssid_len;
/**
* bssid - BSSID
*
* If set, this network block is used only when associating with the AP
* using the configured BSSID
*/
u8 bssid[ETH_ALEN];
/**
* bssid_set - Whether BSSID is configured for this network
*/
int bssid_set;
/**
* psk - WPA pre-shared key (256 bits)
*/
u8 psk[PMK_LEN];
/**
* psk_set - Whether PSK field is configured
*/
int psk_set;
/**
* passphrase - WPA ASCII passphrase
*
* If this is set, psk will be generated using the SSID and passphrase
* configured for the network. ASCII passphrase must be between 8 and
* 63 characters (inclusive).
*/
char *passphrase;
/* Bitfields of allowed Pairwise/Group Ciphers, WPA_CIPHER_* */
/**
* pairwise_cipher - Bitfield of allowed pairwise ciphers, WPA_CIPHER_*
*/
int pairwise_cipher;
/**
* group_cipher - Bitfield of allowed group ciphers, WPA_CIPHER_*
*/
int group_cipher;
/**
* key_mgmt - Bitfield of allowed key management protocols
*
* WPA_KEY_MGMT_*
*/
int key_mgmt;
int proto; /* Bitfield of allowed protocols (WPA_PROTO_*) */
int auth_alg; /* Bitfield of allow authentication algorithms
* (WPA_AUTH_ALG_*) */
int scan_ssid; /* scan this SSID with Probe Requests */
u8 *identity; /* EAP Identity */
/**
* proto - Bitfield of allowed protocols, WPA_PROTO_*
*/
int proto;
/**
* auth_alg - Bitfield of allowed authentication algorithms
*
* WPA_AUTH_ALG_*
*/
int auth_alg;
/**
* scan_ssid - Scan this SSID with Probe Requests
*
* scan_ssid can be used to scan for APs using hidden SSIDs.
* Note: Many drivers do not support this. ap_mode=2 can be used with
* such drivers to use hidden SSIDs.
*/
int scan_ssid;
/**
* identity - EAP Identity
*/
u8 *identity;
/**
* identity_len - EAP Identity length
*/
size_t identity_len;
u8 *anonymous_identity; /* Anonymous EAP Identity (for unencrypted use
* with EAP types that support different
* tunnelled identity, e.g., EAP-TTLS) */
/**
* anonymous_identity - Anonymous EAP Identity
*
* This field is used for unencrypted use with EAP types that support
* different tunnelled identity, e.g., EAP-TTLS, in order to reveal the
* real identity (identity field) only to the authentication server.
*/
u8 *anonymous_identity;
/**
* anonymous_identity_len - Length of anonymous_identity
*/
size_t anonymous_identity_len;
/**
* eappsk - EAP-PSK pre-shared key
*/
u8 *eappsk;
/**
* eappsk_len - EAP-PSK pre-shared key length
*
* This field is always 16 for the current version of EAP-PSK.
*/
size_t eappsk_len;
/**
* nai - User NAI (for EAP-PSK)
*/
u8 *nai;
/**
* nai_len - Length of nai field
*/
size_t nai_len;
u8 *server_nai;
size_t server_nai_len;
/**
* password - Password string for EAP
*/
u8 *password;
/**
* password_len - Length of password field
*/
size_t password_len;
/**
* ca_cert - File path to CA certificate file (PEM/DER)
*
* This file can have one or more trusted CA certificates. If ca_cert
* and ca_path are not included, server certificate will not be
* verified. This is insecure and a trusted CA certificate should
* always be configured when using EAP-TLS/TTLS/PEAP. Full path to the
* file should be used since working directory may change when
* wpa_supplicant is run in the background.
*
* Alternatively, a named configuration blob can be used by setting
* this to blob://<blob name>.
*
* On Windows, trusted CA certificates can be loaded from the system
* certificate store by setting this to cert_store://<name>, e.g.,
* ca_cert="cert_store://CA" or ca_cert="cert_store://ROOT".
*/
u8 *ca_cert;
/**
* ca_path - Directory path for CA certificate files (PEM)
*
* This path may contain multiple CA certificates in OpenSSL format.
* Common use for this is to point to system trusted CA list which is
* often installed into directory like /etc/ssl/certs. If configured,
* these certificates are added to the list of trusted CAs. ca_cert
* may also be included in that case, but it is not required.
*/
u8 *ca_path;
/**
* client_cert - File path to client certificate file (PEM/DER)
*
* This field is used with EAP method that use TLS authentication.
* Usually, this is only configured for EAP-TLS, even though this could
* in theory be used with EAP-TTLS and EAP-PEAP, too. Full path to the
* file should be used since working directory may change when
* wpa_supplicant is run in the background.
*
* Alternatively, a named configuration blob can be used by setting
* this to blob://<blob name>.
*/
u8 *client_cert;
/**
* private_key - File path to client private key file (PEM/DER/PFX)
*
* When PKCS#12/PFX file (.p12/.pfx) is used, client_cert should be
* commented out. Both the private key and certificate will be read
* from the PKCS#12 file in this case. Full path to the file should be
* used since working directory may change when wpa_supplicant is run
* in the background.
*
* Windows certificate store can be used by leaving client_cert out and
* configuring private_key in one of the following formats:
*
* cert://substring_to_match
*
* hash://certificate_thumbprint_in_hex
*
* For example: private_key="hash://63093aa9c47f56ae88334c7b65a4"
*
* Alternatively, a named configuration blob can be used by setting
* this to blob://<blob name>.
*/
u8 *private_key;
/**
* private_key_passwd - Password for private key file
*
* If left out, this will be asked through control interface.
*/
u8 *private_key_passwd;
/**
* dh_file - File path to DH/DSA parameters file (in PEM format)
*
* This is an optional configuration file for setting parameters for an
* ephemeral DH key exchange. In most cases, the default RSA
* authentication does not use this configuration. However, it is
* possible setup RSA to use ephemeral DH key exchange. In addition,
* ciphers with DSA keys always use ephemeral DH keys. This can be used
* to achieve forward secrecy. If the file is in DSA parameters format,
* it will be automatically converted into DH params. Full path to the
* file should be used since working directory may change when
* wpa_supplicant is run in the background.
*
* Alternatively, a named configuration blob can be used by setting
* this to blob://<blob name>.
*/
u8 *dh_file;
/**
* subject_match - Constraint for server certificate subject
*
* This substring is matched against the subject of the authentication
* server certificate. If this string is set, the server sertificate is
* only accepted if it contains this string in the subject. The subject
* string is in following format:
*
* /C=US/ST=CA/L=San Francisco/CN=Test AS/emailAddress=as@n.example.com
*/
u8 *subject_match;
/**
* altsubject_match - Constraint for server certificate alt. subject
*
* This substring is matched against the alternative subject name of
* the authentication server certificate. If this string is set, the
* server sertificate is only accepted if it contains this string in an
* alternative subject name extension.
*
* altSubjectName string is in following format: TYPE:VALUE
*
* Example: DNS:server.example.com
*
* Following types are supported: EMAIL, DNS, URI
*/
u8 *altsubject_match;
/**
* ca_cert2 - File path to CA certificate file (PEM/DER) (Phase 2)
*
* This file can have one or more trusted CA certificates. If ca_cert2
* and ca_path2 are not included, server certificate will not be
* verified. This is insecure and a trusted CA certificate should
* always be configured. Full path to the file should be used since
* working directory may change when wpa_supplicant is run in the
* background.
*
* This field is like ca_cert, but used for phase 2 (inside
* EAP-TTLS/PEAP/FAST tunnel) authentication.
*
* Alternatively, a named configuration blob can be used by setting
* this to blob://<blob name>.
*/
u8 *ca_cert2;
/**
* ca_path2 - Directory path for CA certificate files (PEM) (Phase 2)
*
* This path may contain multiple CA certificates in OpenSSL format.
* Common use for this is to point to system trusted CA list which is
* often installed into directory like /etc/ssl/certs. If configured,
* these certificates are added to the list of trusted CAs. ca_cert
* may also be included in that case, but it is not required.
*
* This field is like ca_path, but used for phase 2 (inside
* EAP-TTLS/PEAP/FAST tunnel) authentication.
*/
u8 *ca_path2;
/**
* client_cert2 - File path to client certificate file
*
* This field is like client_cert, but used for phase 2 (inside
* EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the
* file should be used since working directory may change when
* wpa_supplicant is run in the background.
*
* Alternatively, a named configuration blob can be used by setting
* this to blob://<blob name>.
*/
u8 *client_cert2;
/**
* private_key2 - File path to client private key file
*
* This field is like private_key, but used for phase 2 (inside
* EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the
* file should be used since working directory may change when
* wpa_supplicant is run in the background.
*
* Alternatively, a named configuration blob can be used by setting
* this to blob://<blob name>.
*/
u8 *private_key2;
/**
* private_key2_passwd - Password for private key file
*
* This field is like private_key_passwd, but used for phase 2 (inside
* EAP-TTLS/PEAP/FAST tunnel) authentication.
*/
u8 *private_key2_passwd;
/**
* dh_file2 - File path to DH/DSA parameters file (in PEM format)
*
* This field is like dh_file, but used for phase 2 (inside
* EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the
* file should be used since working directory may change when
* wpa_supplicant is run in the background.
*
* Alternatively, a named configuration blob can be used by setting
* this to blob://<blob name>.
*/
u8 *dh_file2;
/**
* subject_match2 - Constraint for server certificate subject
*
* This field is like subject_match, but used for phase 2 (inside
* EAP-TTLS/PEAP/FAST tunnel) authentication.
*/
u8 *subject_match2;
u8 *eap_methods; /* zero (EAP_TYPE_NONE) terminated list of allowed
* EAP methods or NULL = any */
/**
* altsubject_match2 - Constraint for server certificate alt. subject
*
* This field is like altsubject_match, but used for phase 2 (inside
* EAP-TTLS/PEAP/FAST tunnel) authentication.
*/
u8 *altsubject_match2;
/**
* eap_methods - Allowed EAP methods
*
* Zero (EAP_TYPE_NONE) terminated list of allowed EAP methods or %NULL
* if all methods are accepted.
*/
u8 *eap_methods;
/**
* phase1 - Phase 1 (outer authentication) parameters
*
* String with field-value pairs, e.g., "peapver=0" or
* "peapver=1 peaplabel=1".
*
* 'peapver' can be used to force which PEAP version (0 or 1) is used.
*
* 'peaplabel=1' can be used to force new label, "client PEAP
* encryption", to be used during key derivation when PEAPv1 or newer.
*
* Most existing PEAPv1 implementation seem to be using the old label,
* "client EAP encryption", and wpa_supplicant is now using that as the
* default value.
*
* Some servers, e.g., Radiator, may require peaplabel=1 configuration
* to interoperate with PEAPv1; see eap_testing.txt for more details.
*
* 'peap_outer_success=0' can be used to terminate PEAP authentication
* on tunneled EAP-Success. This is required with some RADIUS servers
* that implement draft-josefsson-pppext-eap-tls-eap-05.txt (e.g.,
* Lucent NavisRadius v4.4.0 with PEAP in "IETF Draft 5" mode).
*
* include_tls_length=1 can be used to force wpa_supplicant to include
* TLS Message Length field in all TLS messages even if they are not
* fragmented.
*
* sim_min_num_chal=3 can be used to configure EAP-SIM to require three
* challenges (by default, it accepts 2 or 3).
*
* fast_provisioning=1 can be used to enable in-line provisioning of
* EAP-FAST credentials (PAC)
*/
char *phase1;
/**
* phase2 - Phase2 (inner authentication with TLS tunnel) parameters
*
* String with field-value pairs, e.g., "auth=MSCHAPV2" for EAP-PEAP or
* "autheap=MSCHAPV2 autheap=MD5" for EAP-TTLS.
*/
char *phase2;
/**
* pcsc - Parameters for PC/SC smartcard interface for USIM and GSM SIM
*
* This field is used to configure PC/SC smartcard interface.
* Currently, the only configuration is whether this field is %NULL (do
* not use PC/SC) or non-NULL (e.g., "") to enable PC/SC.
*
* This field is used for EAP-SIM and EAP-AKA.
*/
char *pcsc;
/**
* pin - PIN for USIM, GSM SIM, and smartcards
*
* This field is used to configure PIN for SIM and smartcards for
* EAP-SIM and EAP-AKA. In addition, this is used with EAP-TLS if a
* smartcard is used for private key operations.
*
* If left out, this will be asked through control interface.
*/
char *pin;
/**
* engine - Enable OpenSSL engine (e.g., for smartcard access)
*
* This is used if private key operations for EAP-TLS are performed
* using a smartcard.
*/
int engine;
/**
* engine_id - Engine ID for OpenSSL engine
*
* "opensc" to select OpenSC engine or "pkcs11" to select PKCS#11
* engine.
*
* This is used if private key operations for EAP-TLS are performed
* using a smartcard.
*/
char *engine_id;
/**
* key_id - Key ID for OpenSSL engine
*
* This is used if private key operations for EAP-TLS are performed
* using a smartcard.
*/
char *key_id;
#define EAPOL_FLAG_REQUIRE_KEY_UNICAST BIT(0)
#define EAPOL_FLAG_REQUIRE_KEY_BROADCAST BIT(1)
int eapol_flags; /* bit field of IEEE 802.1X/EAPOL options */
/**
* eapol_flags - Bit field of IEEE 802.1X/EAPOL options (EAPOL_FLAG_*)
*/
int eapol_flags;
#define NUM_WEP_KEYS 4
#define MAX_WEP_KEY_LEN 16
/**
* wep_key - WEP keys
*/
u8 wep_key[NUM_WEP_KEYS][MAX_WEP_KEY_LEN];
/**
* wep_key_len - WEP key lengths
*/
size_t wep_key_len[NUM_WEP_KEYS];
/**
* wep_tx_keyidx - Default key index for TX frames using WEP
*/
int wep_tx_keyidx;
/* Per SSID variables that are not read from the configuration file */
u8 *otp;
size_t otp_len;
int pending_req_identity, pending_req_password;
char *pending_req_otp;
size_t pending_req_otp_len;
int leap, non_leap;
/**
* 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;
/**
* 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;
/**
* leap - Number of EAP methods using LEAP
*
* This field should be set to 1 if LEAP is enabled. This is used to
* select IEEE 802.11 authentication algorithm.
*/
int leap;
/**
* non_leap - Number of EAP methods not using LEAP
*
* This field should be set to >0 if any EAP method other than LEAP is
* enabled. This is used to select IEEE 802.11 authentication
* algorithm.
*/
int non_leap;
/**
* eap_workaround - EAP workarounds enabled
*
* wpa_supplicant supports number of "EAP workarounds" to work around
* interoperability issues with incorrectly behaving authentication
* servers. This is recommended to be enabled by default because some
* of the issues are present in large number of authentication servers.
*
* Strict EAP conformance mode can be configured by disabling
* workarounds with eap_workaround = 0.
*/
unsigned int eap_workaround;
/**
* pac_file - File path or blob name for the PAC entries (EAP-FAST)
*
* wpa_supplicant will need to be able to create this file and write
* updates to it when PAC is being provisioned or refreshed. Full path
* to the file should be used since working directory may change when
* wpa_supplicant is run in the background.
* Alternatively, a named configuration blob can be used by setting
* this to blob://<blob name>.
*/
char *pac_file;
/**
* mode - IEEE 802.11 operation mode (Infrastucture/IBSS)
*
* 0 = infrastructure (Managed) mode, i.e., associate with an AP.
*
* 1 = IBSS (ad-hoc, peer-to-peer)
*
* Note: IBSS can only be used with key_mgmt NONE (plaintext and
* static WEP) and key_mgmt=WPA-NONE (fixed group key TKIP/CCMP). In
* addition, ap_scan has to be set to 2 for IBSS. WPA-None requires
* following network block options: proto=WPA, key_mgmt=WPA-NONE,
* pairwise=NONE, group=TKIP (or CCMP, but not both), and psk must also
* be set (either directly or using ASCII passphrase).
*/
int mode;
/**
* mschapv2_retry - MSCHAPv2 retry in progress
*
* This field is used internally by EAP-MSCHAPv2 and should not be set
* as part of configuration.
*/
int mschapv2_retry;
/**
* new_password - New password for password update
*
* This field is used during MSCHAPv2 password update. This is normally
* requested from the user through the control interface and not set
* from configuration.
*/
u8 *new_password;
/**
* new_password_len - Length of new_password field
*/
size_t new_password_len;
/**
* disabled - Whether this network is currently disabled
*
* 0 = this network can be used (default).
* 1 = this network block is disabled (can be enabled through
* ctrl_iface, e.g., with wpa_cli or wpa_gui).
*/
int disabled;
};
int wpa_config_allowed_eap_method(struct wpa_ssid *ssid, int method);
const char * wpa_cipher_txt(int cipher);
const char * wpa_key_mgmt_txt(int key_mgmt, int proto);
#endif /* CONFIG_SSID_H */

View file

@ -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 */

View file

@ -12,11 +12,17 @@
* See README and COPYING for more details.
*/
#include <string.h>
#include <sys/types.h>
#include <openssl/md4.h>
#include <openssl/md5.h>
#include <openssl/sha.h>
#include <openssl/des.h>
#include <openssl/aes.h>
#include "common.h"
#include "crypto.h"
#if OPENSSL_VERSION_NUMBER < 0x00907000
#define DES_key_schedule des_key_schedule
@ -27,7 +33,7 @@
#endif /* openssl < 0.9.7 */
void md4_vector(size_t num_elem, const u8 *addr[], size_t *len, u8 *mac)
void md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
MD4_CTX ctx;
int i;
@ -39,17 +45,6 @@ void md4_vector(size_t num_elem, const u8 *addr[], size_t *len, u8 *mac)
}
void md4(const u8 *addr, size_t len, u8 *mac)
{
md4_vector(1, &addr, &len, mac);
}
/**
* @clear: 8 octets (in)
* @key: 7 octets (in) (no parity bits included)
* @cypher: 8 octets (out)
*/
void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
{
u8 pkey[8], next, tmp;
@ -69,3 +64,91 @@ void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
DES_ecb_encrypt((DES_cblock *) clear, (DES_cblock *) cypher, &ks,
DES_ENCRYPT);
}
#ifdef EAP_TLS_FUNCS
void md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
MD5_CTX ctx;
int i;
MD5_Init(&ctx);
for (i = 0; i < num_elem; i++)
MD5_Update(&ctx, addr[i], len[i]);
MD5_Final(mac, &ctx);
}
void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
SHA_CTX ctx;
int i;
SHA1_Init(&ctx);
for (i = 0; i < num_elem; i++)
SHA1_Update(&ctx, addr[i], len[i]);
SHA1_Final(mac, &ctx);
}
void sha1_transform(u8 *state, const u8 data[64])
{
SHA_CTX context;
memset(&context, 0, sizeof(context));
memcpy(&context.h0, state, 5 * 4);
SHA1_Transform(&context, data);
memcpy(state, &context.h0, 5 * 4);
}
void * aes_encrypt_init(const u8 *key, size_t len)
{
AES_KEY *ak;
ak = malloc(sizeof(*ak));
if (ak == NULL)
return NULL;
if (AES_set_encrypt_key(key, 8 * len, ak) < 0) {
free(ak);
return NULL;
}
return ak;
}
void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
{
AES_encrypt(plain, crypt, ctx);
}
void aes_encrypt_deinit(void *ctx)
{
free(ctx);
}
void * aes_decrypt_init(const u8 *key, size_t len)
{
AES_KEY *ak;
ak = malloc(sizeof(*ak));
if (ak == NULL)
return NULL;
if (AES_set_decrypt_key(key, 8 * len, ak) < 0) {
free(ak);
return NULL;
}
return ak;
}
void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
{
AES_decrypt(crypt, plain, ctx);
}
void aes_decrypt_deinit(void *ctx)
{
free(ctx);
}
#endif /* EAP_TLS_FUNCS */

View file

@ -1,8 +1,123 @@
/*
* WPA Supplicant / wrapper functions for crypto libraries
* Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*
* This file defines the cryptographic functions that need to be implemented
* for wpa_supplicant and hostapd. When TLS is not used, internal
* implementation of MD5, SHA1, and AES is used and no external libraries are
* required. When TLS is enabled (e.g., by enabling EAP-TLS or EAP-PEAP), the
* crypto library used by the TLS implementation is expected to be used for
* non-TLS needs, too, in order to save space by not implementing these
* functions twice.
*
* Wrapper code for using each crypto library is in its own file (crypto*.c)
* and one of these files is build and linked in to provide the functions
* defined here.
*/
#ifndef CRYPTO_H
#define CRYPTO_H
/**
* md4_vector - MD4 hash for data vector
* @num_elem: Number of elements in the data vector
* @addr: Pointers to the data areas
* @len: Lengths of the data blocks
* @mac: Buffer for the hash
*/
void md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac);
void md4(const u8 *addr, size_t len, u8 *mac);
/**
* md5_vector - MD5 hash for data vector
* @num_elem: Number of elements in the data vector
* @addr: Pointers to the data areas
* @len: Lengths of the data blocks
* @mac: Buffer for the hash
*/
void md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac);
/**
* sha1_vector - SHA-1 hash for data vector
* @num_elem: Number of elements in the data vector
* @addr: Pointers to the data areas
* @len: Lengths of the data blocks
* @mac: Buffer for the hash
*/
void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len,
u8 *mac);
/**
* sha1_transform - Perform one SHA-1 transform step
* @state: SHA-1 state
* @data: Input data for the SHA-1 transform
*
* This function is used to implement random number generation specified in
* NIST FIPS Publication 186-2 for EAP-SIM. This PRF uses a function that is
* similar to SHA-1, but has different message padding and as such, access to
* just part of the SHA-1 is needed.
*/
void sha1_transform(u8 *state, const u8 data[64]);
/**
* des_encrypt - Encrypt one block with DES
* @clear: 8 octets (in)
* @key: 7 octets (in) (no parity bits included)
* @cypher: 8 octets (out)
*/
void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher);
/**
* aes_encrypt_init - Initialize AES for encryption
* @key: Encryption key
* @len: Key length in bytes (usually 16, i.e., 128 bits)
* Returns: Pointer to context data or %NULL on failure
*/
void * aes_encrypt_init(const u8 *key, size_t len);
/**
* aes_encrypt - Encrypt one AES block
* @ctx: Context pointer from aes_encrypt_init()
* @plain: Plaintext data to be encrypted (16 bytes)
* @crypt: Buffer for the encrypted data (16 bytes)
*/
void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt);
/**
* aes_encrypt_deinit - Deinitialize AES encryption
* @ctx: Context pointer from aes_encrypt_init()
*/
void aes_encrypt_deinit(void *ctx);
/**
* aes_decrypt_init - Initialize AES for decryption
* @key: Decryption key
* @len: Key length in bytes (usually 16, i.e., 128 bits)
* Returns: Pointer to context data or %NULL on failure
*/
void * aes_decrypt_init(const u8 *key, size_t len);
/**
* aes_decrypt - Decrypt one AES block
* @ctx: Context pointer from aes_encrypt_init()
* @crypt: Encrypted data (16 bytes)
* @plain: Buffer for the decrypted data (16 bytes)
*/
void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain);
/**
* aes_decrypt_deinit - Deinitialize AES decryption
* @ctx: Context pointer from aes_encrypt_init()
*/
void aes_decrypt_deinit(void *ctx);
#endif /* CRYPTO_H */

View file

@ -0,0 +1,163 @@
/*
* WPA Supplicant / wrapper functions for libgcrypt
* Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include <stdio.h>
#include <sys/types.h>
#include <gcrypt.h>
#include "common.h"
#include "crypto.h"
void md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
gcry_md_hd_t hd;
unsigned char *p;
int i;
if (gcry_md_open(&hd, GCRY_MD_MD4, 0) != GPG_ERR_NO_ERROR)
return;
for (i = 0; i < num_elem; i++)
gcry_md_write(hd, addr[i], len[i]);
p = gcry_md_read(hd, GCRY_MD_MD4);
if (p)
memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_MD4));
gcry_md_close(hd);
}
void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
{
gcry_cipher_hd_t hd;
u8 pkey[8], next, tmp;
int i;
/* Add parity bits to the key */
next = 0;
for (i = 0; i < 7; i++) {
tmp = key[i];
pkey[i] = (tmp >> i) | next | 1;
next = tmp << (7 - i);
}
pkey[i] = next | 1;
gcry_cipher_open(&hd, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
gcry_err_code(gcry_cipher_setkey(hd, pkey, 8));
gcry_cipher_encrypt(hd, cypher, 8, clear, 8);
gcry_cipher_close(hd);
}
#ifdef EAP_TLS_FUNCS
void md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
gcry_md_hd_t hd;
unsigned char *p;
int i;
if (gcry_md_open(&hd, GCRY_MD_MD5, 0) != GPG_ERR_NO_ERROR)
return;
for (i = 0; i < num_elem; i++)
gcry_md_write(hd, addr[i], len[i]);
p = gcry_md_read(hd, GCRY_MD_MD5);
if (p)
memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_MD5));
gcry_md_close(hd);
}
void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
gcry_md_hd_t hd;
unsigned char *p;
int i;
if (gcry_md_open(&hd, GCRY_MD_SHA1, 0) != GPG_ERR_NO_ERROR)
return;
for (i = 0; i < num_elem; i++)
gcry_md_write(hd, addr[i], len[i]);
p = gcry_md_read(hd, GCRY_MD_SHA1);
if (p)
memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_SHA1));
gcry_md_close(hd);
}
void sha1_transform(u8 *state, const u8 data[64])
{
/* FIX: how to do this with libgcrypt? */
}
void * aes_encrypt_init(const u8 *key, size_t len)
{
gcry_cipher_hd_t hd;
if (gcry_cipher_open(&hd, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0) !=
GPG_ERR_NO_ERROR) {
printf("cipher open failed\n");
return NULL;
}
if (gcry_cipher_setkey(hd, key, len) != GPG_ERR_NO_ERROR) {
printf("setkey failed\n");
gcry_cipher_close(hd);
return NULL;
}
return hd;
}
void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
{
gcry_cipher_hd_t hd = ctx;
gcry_cipher_encrypt(hd, crypt, 16, plain, 16);
}
void aes_encrypt_deinit(void *ctx)
{
gcry_cipher_hd_t hd = ctx;
gcry_cipher_close(hd);
}
void * aes_decrypt_init(const u8 *key, size_t len)
{
gcry_cipher_hd_t hd;
if (gcry_cipher_open(&hd, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0) !=
GPG_ERR_NO_ERROR)
return NULL;
if (gcry_cipher_setkey(hd, key, len) != GPG_ERR_NO_ERROR) {
gcry_cipher_close(hd);
return NULL;
}
return hd;
}
void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
{
gcry_cipher_hd_t hd = ctx;
gcry_cipher_decrypt(hd, plain, 16, crypt, 16);
}
void aes_decrypt_deinit(void *ctx)
{
gcry_cipher_hd_t hd = ctx;
gcry_cipher_close(hd);
}
#endif /* EAP_TLS_FUNCS */

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,17 @@
/*
* WPA Supplicant / UNIX domain socket -based control interface
* Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef CTRL_IFACE_H
#define CTRL_IFACE_H
@ -7,6 +21,9 @@ int wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s);
void wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s);
void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s, int level,
char *buf, size_t len);
void wpa_supplicant_ctrl_iface_wait(struct wpa_supplicant *wpa_s);
int wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global);
void wpa_supplicant_global_ctrl_iface_deinit(struct wpa_global *global);
#else /* CONFIG_CTRL_IFACE */
@ -26,6 +43,22 @@ wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s, int level,
{
}
static inline void
wpa_supplicant_ctrl_iface_wait(struct wpa_supplicant *wpa_s)
{
}
static inline int
wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
{
return 0;
}
static inline void
wpa_supplicant_global_ctrl_iface_deinit(struct wpa_global *global)
{
}
#endif /* CONFIG_CTRL_IFACE */
#endif /* CTRL_IFACE_H */

View file

@ -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

View file

@ -1,14 +1,131 @@
/*
* WPA Supplicant - Common definitions
* Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef DEFS_H
#define DEFS_H
#ifdef CONFIG_NATIVE_WINDOWS
#ifdef FALSE
#undef FALSE
#endif
#ifdef TRUE
#undef TRUE
#endif
#endif /* CONFIG_NATIVE_WINDOWS */
typedef enum { FALSE = 0, TRUE = 1 } Boolean;
typedef enum { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP } wpa_alg;
typedef enum { CIPHER_NONE, CIPHER_WEP40, CIPHER_TKIP, CIPHER_CCMP,
CIPHER_WEP104 } wpa_cipher;
typedef enum { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE,
KEY_MGMT_802_1X_NO_WPA, KEY_MGMT_WPA_NONE } wpa_key_mgmt;
/**
* enum wpa_states - wpa_supplicant state
*
* These enumeration values are used to indicate the current wpa_supplicant
* state (wpa_s->wpa_state). The current state can be retrieved with
* wpa_supplicant_get_state() function and the state can be changed by calling
* wpa_supplicant_set_state(). In WPA state machine (wpa.c and preauth.c), the
* wrapper functions wpa_sm_get_state() and wpa_sm_set_state() should be used
* to access the state variable.
*/
typedef enum {
/**
* WPA_DISCONNECTED - Disconnected state
*
* This state indicates that client is not associated, but is likely to
* start looking for an access point. This state is entered when a
* connection is lost.
*/
WPA_DISCONNECTED,
/**
* WPA_INACTIVE - Inactive state (wpa_supplicant disabled)
*
* This state is entered if there are no enabled networks in the
* configuration. wpa_supplicant is not trying to associate with a new
* network and external interaction (e.g., ctrl_iface call to add or
* enable a network) is needed to start association.
*/
WPA_INACTIVE,
/**
* WPA_SCANNING - Scanning for a network
*
* This state is entered when wpa_supplicant starts scanning for a
* network.
*/
WPA_SCANNING,
/**
* WPA_ASSOCIATING - Trying to associate with a BSS/SSID
*
* This state is entered when wpa_supplicant has found a suitable BSS
* to associate with and the driver is configured to try to associate
* with this BSS in ap_scan=1 mode. When using ap_scan=2 mode, this
* state is entered when the driver is configured to try to associate
* with a network using the configured SSID and security policy.
*/
WPA_ASSOCIATING,
/**
* WPA_ASSOCIATED - Association completed
*
* This state is entered when the driver reports that association has
* been successfully completed with an AP. If IEEE 802.1X is used
* (with or without WPA/WPA2), wpa_supplicant remains in this state
* until the IEEE 802.1X/EAPOL authentication has been completed.
*/
WPA_ASSOCIATED,
/**
* WPA_4WAY_HANDSHAKE - WPA 4-Way Key Handshake in progress
*
* This state is entered when WPA/WPA2 4-Way Handshake is started. In
* case of WPA-PSK, this happens when receiving the first EAPOL-Key
* frame after association. In case of WPA-EAP, this state is entered
* when the IEEE 802.1X/EAPOL authentication has been completed.
*/
WPA_4WAY_HANDSHAKE,
/**
* WPA_GROUP_HANDSHAKE - WPA Group Key Handshake in progress
*
* This state is entered when 4-Way Key Handshake has been completed
* (i.e., when the supplicant sends out message 4/4) and when Group
* Key rekeying is started by the AP (i.e., when supplicant receives
* message 1/2).
*/
WPA_GROUP_HANDSHAKE,
/**
* WPA_COMPLETED - All authentication completed
*
* This state is entered when the full authentication process is
* completed. In case of WPA2, this happens when the 4-Way Handshake is
* successfully completed. With WPA, this state is entered after the
* Group Key Handshake; with IEEE 802.1X (non-WPA) connection is
* completed after dynamic keys are received (or if not used, after
* the EAP authentication has been completed). With static WEP keys and
* plaintext connections, this state is entered when an association
* has been completed.
*
* This state indicates that the supplicant has completed its
* processing for the association phase and that data connection is
* fully configured.
*/
WPA_COMPLETED
} wpa_states;
#endif /* DEFS_H */

View file

@ -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
*/

View file

@ -0,0 +1,409 @@
/**
\page ctrl_iface_page Control interface
%wpa_supplicant implements a control interface that can be used by
external programs to control the operations of the %wpa_supplicant
daemon and to get status information and event notifications. There is
a small C library, in a form of a single C file, wpa_ctrl.c, that
provides helper functions to facilitate the use of the control
interface. External programs can link this file into them and then use
the library functions documented in wpa_ctrl.h to interact with
%wpa_supplicant. This library can also be used with C++. wpa_cli.c and
wpa_gui are example programs using this library.
There are multiple mechanisms for inter-process communication. For
example, Linux version of %wpa_supplicant is using UNIX domain sockets
for the control interface and Windows version UDP sockets. The use of
the functions defined in wpa_ctrl.h can be used to hide the details of
the used IPC from external programs.
\section using_ctrl_iface Using the control interface
External programs, e.g., a GUI or a configuration utility, that need to
communicate with %wpa_supplicant should link in wpa_ctrl.c. This
allows them to use helper functions to open connection to the control
interface with wpa_ctrl_open() and to send commands with
wpa_ctrl_request().
%wpa_supplicant uses the control interface for two types of communication:
commands and unsolicited event messages. Commands are a pair of
messages, a request from the external program and a response from
%wpa_supplicant. These can be executed using wpa_ctrl_request().
Unsolicited event messages are sent by %wpa_supplicant to the control
interface connection without specific request from the external program
for receiving each message. However, the external program needs to
attach to the control interface with wpa_ctrl_attach() to receive these
unsolicited messages.
If the control interface connection is used both for commands and
unsolicited event messages, there is potential for receiving an
unsolicited message between the command request and response.
wpa_ctrl_request() caller will need to supply a callback, msg_cb,
for processing these messages. Often it is easier to open two
control interface connections by calling wpa_ctrl_open() twice and
then use one of the connections for commands and the other one for
unsolicited messages. This way command request/response pairs will
not be broken by unsolicited messages. wpa_cli is an example of how
to use only one connection for both purposes and wpa_gui demonstrates
how to use two separate connections.
Once the control interface connection is not needed anymore, it should
be closed by calling wpa_ctrl_close(). If the connection was used for
unsolicited event messages, it should be first detached by calling
wpa_ctrl_detach().
\section ctrl_iface_cmds Control interface commands
Following commands can be used with wpa_ctrl_request():
\subsection ctrl_iface_PING PING
This command can be used to test whether %wpa_supplicant is replying
to the control interface commands. The expected reply is \c PONG if the
connection is open and %wpa_supplicant is processing commands.
\subsection ctrl_iface_MIB MIB
Request a list of MIB variables (dot1x, dot11). The output is a text
block with each line in \c variable=value format. For example:
\verbatim
dot11RSNAOptionImplemented=TRUE
dot11RSNAPreauthenticationImplemented=TRUE
dot11RSNAEnabled=FALSE
dot11RSNAPreauthenticationEnabled=FALSE
dot11RSNAConfigVersion=1
dot11RSNAConfigPairwiseKeysSupported=5
dot11RSNAConfigGroupCipherSize=128
dot11RSNAConfigPMKLifetime=43200
dot11RSNAConfigPMKReauthThreshold=70
dot11RSNAConfigNumberOfPTKSAReplayCounters=1
dot11RSNAConfigSATimeout=60
dot11RSNAAuthenticationSuiteSelected=00-50-f2-2
dot11RSNAPairwiseCipherSelected=00-50-f2-4
dot11RSNAGroupCipherSelected=00-50-f2-4
dot11RSNAPMKIDUsed=
dot11RSNAAuthenticationSuiteRequested=00-50-f2-2
dot11RSNAPairwiseCipherRequested=00-50-f2-4
dot11RSNAGroupCipherRequested=00-50-f2-4
dot11RSNAConfigNumberOfGTKSAReplayCounters=0
dot11RSNA4WayHandshakeFailures=0
dot1xSuppPaeState=5
dot1xSuppHeldPeriod=60
dot1xSuppAuthPeriod=30
dot1xSuppStartPeriod=30
dot1xSuppMaxStart=3
dot1xSuppSuppControlledPortStatus=Authorized
dot1xSuppBackendPaeState=2
dot1xSuppEapolFramesRx=0
dot1xSuppEapolFramesTx=440
dot1xSuppEapolStartFramesTx=2
dot1xSuppEapolLogoffFramesTx=0
dot1xSuppEapolRespFramesTx=0
dot1xSuppEapolReqIdFramesRx=0
dot1xSuppEapolReqFramesRx=0
dot1xSuppInvalidEapolFramesRx=0
dot1xSuppEapLengthErrorFramesRx=0
dot1xSuppLastEapolFrameVersion=0
dot1xSuppLastEapolFrameSource=00:00:00:00:00:00
\endverbatim
\subsection ctrl_iface_STATUS STATUS
Request current WPA/EAPOL/EAP status information. The output is a text
block with each line in \c variable=value format. For example:
\verbatim
bssid=02:00:01:02:03:04
ssid=test network
pairwise_cipher=CCMP
group_cipher=CCMP
key_mgmt=WPA-PSK
wpa_state=COMPLETED
ip_address=192.168.1.21
Supplicant PAE state=AUTHENTICATED
suppPortStatus=Authorized
EAP state=SUCCESS
\endverbatim
\subsection ctrl_iface_STATUS-VERBOSE STATUS-VERBOSE
Same as STATUS, but with more verbosity (i.e., more \c variable=value pairs).
\verbatim
bssid=02:00:01:02:03:04
ssid=test network
pairwise_cipher=CCMP
group_cipher=CCMP
key_mgmt=WPA-PSK
wpa_state=COMPLETED
ip_address=192.168.1.21
Supplicant PAE state=AUTHENTICATED
suppPortStatus=Authorized
heldPeriod=60
authPeriod=30
startPeriod=30
maxStart=3
portControl=Auto
Supplicant Backend state=IDLE
EAP state=SUCCESS
reqMethod=0
methodState=NONE
decision=COND_SUCC
ClientTimeout=60
\endverbatim
\subsection ctrl_iface_PMKSA PMKSA
Show PMKSA cache
\verbatim
Index / AA / PMKID / expiration (in seconds) / opportunistic
1 / 02:00:01:02:03:04 / 000102030405060708090a0b0c0d0e0f / 41362 / 0
2 / 02:00:01:33:55:77 / 928389281928383b34afb34ba4212345 / 362 / 1
\endverbatim
\subsection ctrl_iface_SET SET <variable> <value>
Set variables:
- EAPOL::heldPeriod
- EAPOL::authPeriod
- EAPOL::startPeriod
- EAPOL::maxStart
- dot11RSNAConfigPMKLifetime
- dot11RSNAConfigPMKReauthThreshold
- dot11RSNAConfigSATimeout
Example command:
\verbatim
SET EAPOL::heldPeriod 45
\endverbatim
\subsection ctrl_iface_LOGON LOGON
IEEE 802.1X EAPOL state machine logon.
\subsection ctrl_iface_LOGOFF LOGOFF
IEEE 802.1X EAPOL state machine logoff.
\subsection ctrl_iface_REASSOCIATE REASSOCIATE
Force reassociation.
\subsection ctrl_iface_PREAUTH PREAUTH <BSSID>
Start pre-authentication with the given BSSID.
\subsection ctrl_iface_ATTACH ATTACH
Attach the connection as a monitor for unsolicited events. This can
be done with wpa_ctrl_attach().
\subsection ctrl_iface_DETACH DETACH
Detach the connection as a monitor for unsolicited events. This can
be done with wpa_ctrl_detach().
\subsection ctrl_iface_LEVEL LEVEL <debug level>
Change debug level.
\subsection ctrl_iface_RECONFIGURE RECONFIGURE
Force %wpa_supplicant to re-read its configuration data.
\subsection ctrl_iface_TERMINATE TERMINATE
Terminate %wpa_supplicant process.
\subsection ctrl_iface_BSSID BSSID <network id> <BSSID>
Set preferred BSSID for a network. Network id can be received from the
\c LIST_NETWORKS command output.
\subsection ctrl_iface_LIST_NETWORKS LIST_NETWORKS
List configured networks.
\verbatim
network id / ssid / bssid / flags
0 example network any [CURRENT]
\endverbatim
(note: fields are separated with tabs)
\subsection ctrl_iface_DISCONNECT DISCONNECT
Disconnect and wait for \c REASSOCIATE command before connecting.
\subsection ctrl_iface_SCAN SCAN
Request a new BSS scan.
\subsection ctrl_iface_SCAN_RESULTS SCAN_RESULTS
Get the latest scan results.
\verbatim
bssid / frequency / signal level / flags / ssid
00:09:5b:95:e0:4e 2412 208 [WPA-PSK-CCMP] jkm private
02:55:24:33:77:a3 2462 187 [WPA-PSK-TKIP] testing
00:09:5b:95:e0:4f 2412 209 jkm guest
\endverbatim
(note: fields are separated with tabs)
\subsection ctrl_iface_SELECT_NETWORK SELECT_NETWORK <network id>
Select a network (disable others). Network id can be received from the
\c LIST_NETWORKS command output.
\subsection ctrl_iface_ENABLE_NETWORK ENABLE_NETWORK <network id>
Enable a network. Network id can be received from the
\c LIST_NETWORKS command output.
\subsection ctrl_iface_DISABLE_NETWORK DISABLE_NETWORK <network id>
Disable a network. Network id can be received from the
\c LIST_NETWORKS command output.
\subsection ctrl_iface_ADD_NETWORK ADD_NETWORK
Add a new network. This command creates a new network with empty
configuration. The new network is disabled and once it has been
configured it can be enabled with \c ENABLE_NETWORK command. \c ADD_NETWORK
returns the network id of the new network or FAIL on failure.
\subsection ctrl_iface_REMOVE_NETWORK REMOVE_NETWORK <network id>
Remove a network. Network id can be received from the
\c LIST_NETWORKS command output.
\subsection ctrl_iface_SET_NETWORK SET_NETWORK <network id> <variable> <value>
Set network variables. Network id can be received from the
\c LIST_NETWORKS command output.
This command uses the same variables and data formats as the
configuration file. See example wpa_supplicant.conf for more details.
- ssid (network name, SSID)
- psk (WPA passphrase or pre-shared key)
- key_mgmt (key management protocol)
- identity (EAP identity)
- password (EAP password)
- ...
\subsection ctrl_iface_GET_NETWORK GET_NETWORK <network id> <variable>
Get network variables. Network id can be received from the
\c LIST_NETWORKS command output.
\subsection ctrl_iface_SAVE_CONFIG SAVE_CONFIG
Save the current configuration.
\section ctrl_iface_interactive Interactive requests
If %wpa_supplicant needs additional information during authentication
(e.g., password), it will use a specific prefix, \c CTRL-REQ-
(\a WPA_CTRL_REQ macro) in an unsolicited event message. An external
program, e.g., a GUI, can provide such information by using
\c CTRL-RSP- (\a WPA_CTRL_RSP macro) prefix in a command with matching
field name.
The following fields can be requested in this way from the user:
- IDENTITY (EAP identity/user name)
- PASSWORD (EAP password)
- NEW_PASSWORD (New password if the server is requesting password change)
- PIN (PIN code for accessing a SIM or smartcard)
- OTP (one-time password; like password, but the value is used only once)
- PASSPHRASE (passphrase for a private key file)
\verbatim
CTRL-REQ-<field name>-<network id>-<human readable text>
CTRL-RSP-<field name>-<network id>-<value>
\endverbatim
For example, request from %wpa_supplicant:
\verbatim
CTRL-REQ-PASSWORD-1-Password needed for SSID test-network
\endverbatim
And a matching reply from the GUI:
\verbatim
CTRL-RSP-PASSWORD-1-secret
\endverbatim
\subsection ctrl_iface_GET_CAPABILITY GET_CAPABILITY <option>
Get list of supported functionality (eap, pairwise, group,
proto). Supported functionality is shown as space separate lists of
values used in the same format as in %wpa_supplicant configuration.
Example request/reply pairs:
\verbatim
GET_CAPABILITY eap
AKA FAST GTC LEAP MD5 MSCHAPV2 OTP PAX PEAP PSK SIM TLS TTLS
\endverbatim
\verbatim
GET_CAPABILITY pairwise
CCMP TKIP NONE
\endverbatim
\verbatim
GET_CAPABILITY group
CCMP TKIP WEP104 WEP40
\endverbatim
\verbatim
GET_CAPABILITY key_mgmt
WPA-PSK WPA-EAP IEEE8021X NONE
\endverbatim
\verbatim
GET_CAPABILITY proto
RSN WPA
\endverbatim
\verbatim
GET_CAPABILITY auth_alg
OPEN SHARED LEAP
\endverbatim
*/

View file

@ -0,0 +1,25 @@
all: man html pdf
FILES += wpa_background
FILES += wpa_cli
FILES += wpa_passphrase
FILES += wpa_supplicant.conf
FILES += wpa_supplicant
man:
for i in $(FILES); do docbook2man $$i.sgml; done
html:
for i in $(FILES); do docbook2html $$i.sgml && \
mv index.html $$i.html; done
pdf:
for i in $(FILES); do docbook2pdf $$i.sgml; done
clean:
rm -f wpa_background.8 wpa_cli.8 wpa_passphrase.8 wpa_supplicant.8
rm -f wpa_supplicant.conf.5
rm -f manpage.links manpage.refs
rm -f $(FILES:%=%.pdf)
rm -f $(FILES:%=%.html)

View file

@ -0,0 +1,84 @@
.\" This manpage has been automatically generated by docbook2man
.\" from a DocBook document. This tool can be found at:
.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/>
.\" Please send any bug reports, improvements, comments, patches,
.\" etc. to Steve Cheng <steve@ggi-project.org>.
.TH "WPA_BACKGROUND" "8" "08 February 2006" "" ""
.SH NAME
wpa_background \- Background information on Wi-Fi Protected Access and IEEE 802.11i
.SH "WPA"
.PP
The original security mechanism of IEEE 802.11 standard was
not designed to be strong and has proven to be insufficient for
most networks that require some kind of security. Task group I
(Security) of IEEE 802.11 working group
(http://www.ieee802.org/11/) has worked to address the flaws of
the base standard and has in practice completed its work in May
2004. The IEEE 802.11i amendment to the IEEE 802.11 standard was
approved in June 2004 and published in July 2004.
.PP
Wi-Fi Alliance (http://www.wi-fi.org/) used a draft version
of the IEEE 802.11i work (draft 3.0) to define a subset of the
security enhancements that can be implemented with existing wlan
hardware. This is called Wi-Fi Protected Access<TM> (WPA). This
has now become a mandatory component of interoperability testing
and certification done by Wi-Fi Alliance. Wi-Fi provides
information about WPA at its web site
(http://www.wi-fi.org/OpenSection/protected_access.asp).
.PP
IEEE 802.11 standard defined wired equivalent privacy (WEP)
algorithm for protecting wireless networks. WEP uses RC4 with
40-bit keys, 24-bit initialization vector (IV), and CRC32 to
protect against packet forgery. All these choices have proven to
be insufficient: key space is too small against current attacks,
RC4 key scheduling is insufficient (beginning of the pseudorandom
stream should be skipped), IV space is too small and IV reuse
makes attacks easier, there is no replay protection, and non-keyed
authentication does not protect against bit flipping packet
data.
.PP
WPA is an intermediate solution for the security issues. It
uses Temporal Key Integrity Protocol (TKIP) to replace WEP. TKIP
is a compromise on strong security and possibility to use existing
hardware. It still uses RC4 for the encryption like WEP, but with
per-packet RC4 keys. In addition, it implements replay protection,
keyed packet authentication mechanism (Michael MIC).
.PP
Keys can be managed using two different mechanisms. WPA can
either use an external authentication server (e.g., RADIUS) and
EAP just like IEEE 802.1X is using or pre-shared keys without need
for additional servers. Wi-Fi calls these "WPA-Enterprise" and
"WPA-Personal", respectively. Both mechanisms will generate a
master session key for the Authenticator (AP) and Supplicant
(client station).
.PP
WPA implements a new key handshake (4-Way Handshake and
Group Key Handshake) for generating and exchanging data encryption
keys between the Authenticator and Supplicant. This handshake is
also used to verify that both Authenticator and Supplicant know
the master session key. These handshakes are identical regardless
of the selected key management mechanism (only the method for
generating master session key changes).
.SH "IEEE 802.11I / WPA2"
.PP
The design for parts of IEEE 802.11i that were not included
in WPA has finished (May 2004) and this amendment to IEEE 802.11
was approved in June 2004. Wi-Fi Alliance is using the final IEEE
802.11i as a new version of WPA called WPA2. This includes, e.g.,
support for more robust encryption algorithm (CCMP: AES in Counter
mode with CBC-MAC) to replace TKIP and optimizations for handoff
(reduced number of messages in initial key handshake,
pre-authentication, and PMKSA caching).
.SH "SEE ALSO"
.PP
\fBwpa_supplicant\fR(8)
.SH "LEGAL"
.PP
wpa_supplicant is copyright (c) 2003-2005,
Jouni Malinen <jkmaline@cc.hut.fi> and
contributors.
All Rights Reserved.
.PP
This program is dual-licensed under both the GPL version 2
and BSD license. Either license may be used at your option.

View file

@ -0,0 +1,101 @@
<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
<refentry>
<refmeta>
<refentrytitle>wpa_background</refentrytitle>
<manvolnum>8</manvolnum>
</refmeta>
<refnamediv>
<refname>wpa_background</refname>
<refpurpose>Background information on Wi-Fi Protected Access and IEEE 802.11i</refpurpose>
</refnamediv>
<refsect1>
<title>WPA</title>
<para>The original security mechanism of IEEE 802.11 standard was
not designed to be strong and has proven to be insufficient for
most networks that require some kind of security. Task group I
(Security) of IEEE 802.11 working group
(http://www.ieee802.org/11/) has worked to address the flaws of
the base standard and has in practice completed its work in May
2004. The IEEE 802.11i amendment to the IEEE 802.11 standard was
approved in June 2004 and published in July 2004.</para>
<para>Wi-Fi Alliance (http://www.wi-fi.org/) used a draft version
of the IEEE 802.11i work (draft 3.0) to define a subset of the
security enhancements that can be implemented with existing wlan
hardware. This is called Wi-Fi Protected Access&lt;TM&gt; (WPA). This
has now become a mandatory component of interoperability testing
and certification done by Wi-Fi Alliance. Wi-Fi provides
information about WPA at its web site
(http://www.wi-fi.org/OpenSection/protected_access.asp).</para>
<para>IEEE 802.11 standard defined wired equivalent privacy (WEP)
algorithm for protecting wireless networks. WEP uses RC4 with
40-bit keys, 24-bit initialization vector (IV), and CRC32 to
protect against packet forgery. All these choices have proven to
be insufficient: key space is too small against current attacks,
RC4 key scheduling is insufficient (beginning of the pseudorandom
stream should be skipped), IV space is too small and IV reuse
makes attacks easier, there is no replay protection, and non-keyed
authentication does not protect against bit flipping packet
data.</para>
<para>WPA is an intermediate solution for the security issues. It
uses Temporal Key Integrity Protocol (TKIP) to replace WEP. TKIP
is a compromise on strong security and possibility to use existing
hardware. It still uses RC4 for the encryption like WEP, but with
per-packet RC4 keys. In addition, it implements replay protection,
keyed packet authentication mechanism (Michael MIC).</para>
<para>Keys can be managed using two different mechanisms. WPA can
either use an external authentication server (e.g., RADIUS) and
EAP just like IEEE 802.1X is using or pre-shared keys without need
for additional servers. Wi-Fi calls these "WPA-Enterprise" and
"WPA-Personal", respectively. Both mechanisms will generate a
master session key for the Authenticator (AP) and Supplicant
(client station).</para>
<para>WPA implements a new key handshake (4-Way Handshake and
Group Key Handshake) for generating and exchanging data encryption
keys between the Authenticator and Supplicant. This handshake is
also used to verify that both Authenticator and Supplicant know
the master session key. These handshakes are identical regardless
of the selected key management mechanism (only the method for
generating master session key changes).</para>
</refsect1>
<refsect1>
<title>IEEE 802.11i / WPA2</title>
<para>The design for parts of IEEE 802.11i that were not included
in WPA has finished (May 2004) and this amendment to IEEE 802.11
was approved in June 2004. Wi-Fi Alliance is using the final IEEE
802.11i as a new version of WPA called WPA2. This includes, e.g.,
support for more robust encryption algorithm (CCMP: AES in Counter
mode with CBC-MAC) to replace TKIP and optimizations for handoff
(reduced number of messages in initial key handshake,
pre-authentication, and PMKSA caching).</para>
</refsect1>
<refsect1>
<title>See Also</title>
<para>
<citerefentry>
<refentrytitle>wpa_supplicant</refentrytitle>
<manvolnum>8</manvolnum>
</citerefentry>
</para>
</refsect1>
<refsect1>
<title>Legal</title>
<para>wpa_supplicant is copyright (c) 2003-2005,
Jouni Malinen <email>jkmaline@cc.hut.fi</email> and
contributors.
All Rights Reserved.</para>
<para>This program is dual-licensed under both the GPL version 2
and BSD license. Either license may be used at your option.</para>
</refsect1>
</refentry>

View file

@ -0,0 +1,202 @@
.\" This manpage has been automatically generated by docbook2man
.\" from a DocBook document. This tool can be found at:
.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/>
.\" Please send any bug reports, improvements, comments, patches,
.\" etc. to Steve Cheng <steve@ggi-project.org>.
.TH "WPA_CLI" "8" "08 February 2006" "" ""
.SH NAME
wpa_cli \- WPA command line client
.SH SYNOPSIS
\fBwpa_cli\fR [ \fB-p \fIpath to ctrl sockets\fB\fR ] [ \fB-i \fIifname\fB\fR ] [ \fB-hvB\fR ] [ \fB-a \fIaction file\fB\fR ] [ \fB-P \fIpid file\fB\fR ] [ \fB\fIcommand ...\fB\fR ]
.SH "OVERVIEW"
.PP
wpa_cli is a text-based frontend program for interacting
with wpa_supplicant. It is used to query current status, change
configuration, trigger events, and request interactive user
input.
.PP
wpa_cli can show the current authentication status, selected
security mode, dot11 and dot1x MIBs, etc. In addition, it can
configure some variables like EAPOL state machine parameters and
trigger events like reassociation and IEEE 802.1X
logoff/logon. wpa_cli provides a user interface to request
authentication information, like username and password, if these
are not included in the configuration. This can be used to
implement, e.g., one-time-passwords or generic token card
authentication where the authentication is based on a
challenge-response that uses an external device for generating the
response.
.PP
The control interface of wpa_supplicant can be configured to
allow non-root user access (ctrl_interface_group in the
configuration file). This makes it possible to run wpa_cli with a
normal user account.
.PP
wpa_cli supports two modes: interactive and command
line. Both modes share the same command set and the main
difference is in interactive mode providing access to unsolicited
messages (event messages, username/password requests).
.PP
Interactive mode is started when wpa_cli is executed without
including the command as a command line parameter. Commands are
then entered on the wpa_cli prompt. In command line mode, the same
commands are entered as command line arguments for wpa_cli.
.SH "INTERACTIVE AUTHENTICATION PARAMETERS REQUEST"
.PP
When wpa_supplicant need authentication parameters, like
username and password, which are not present in the configuration
file, it sends a request message to all attached frontend programs,
e.g., wpa_cli in interactive mode. wpa_cli shows these requests
with "CTRL-REQ-<type>-<id>:<text>"
prefix. <type> is IDENTITY, PASSWORD, or OTP
(one-time-password). <id> is a unique identifier for the
current network. <text> is description of the request. In
case of OTP request, it includes the challenge from the
authentication server.
.PP
The reply to these requests can be given with 'identity',
'password', and 'otp' commands. <id> needs to be copied from the
the matching request. 'password' and 'otp' commands can be used
regardless of whether the request was for PASSWORD or OTP. The
main difference between these two commands is that values given
with 'password' are remembered as long as wpa_supplicant is
running whereas values given with 'otp' are used only once and
then forgotten, i.e., wpa_supplicant will ask frontend for a new
value for every use. This can be used to implement
one-time-password lists and generic token card -based
authentication.
.PP
Example request for password and a matching reply:
.sp
.RS
.nf
CTRL-REQ-PASSWORD-1:Password needed for SSID foobar
> password 1 mysecretpassword
.fi
.RE
.PP
Example request for generic token card challenge-response:
.sp
.RS
.nf
CTRL-REQ-OTP-2:Challenge 1235663 needed for SSID foobar
> otp 2 9876
.fi
.RE
.SH "COMMAND ARGUMENTS"
.TP
\fB-p path\fR
Change the path where control sockets should
be found.
.TP
\fB-i ifname\fR
Specify the interface that is being
configured. By default, choose the first interface found with
a control socket in the socket path.
.TP
\fB-h\fR
Help. Show a usage message.
.TP
\fB-v\fR
Show version information.
.TP
\fB-B\fR
Run as a daemon in the background.
.TP
\fB-a file\fR
Run in daemon mode executing the action file
based on events from wpa_supplicant. The specified file will
be executed with the first argument set to interface name and
second to "CONNECT" or "DISCONNECT" depending on the event.
This can be used
.TP
\fB-P file\fR
Set the location of the PID
file.
.TP
\fBcommand\fR
Run a command. The available commands are
listed in the next section.
.SH "COMMANDS"
.PP
The following commands are available:
.TP
\fBstatus\fR
get current WPA/EAPOL/EAP status
.TP
\fBmib\fR
get MIB variables (dot1x, dot11)
.TP
\fBhelp\fR
show this usage help
.TP
\fBinterface [ifname]\fR
show interfaces/select interface
.TP
\fBlevel <debug level>\fR
change debug level
.TP
\fBlicense\fR
show full wpa_cli license
.TP
\fBlogoff\fR
IEEE 802.1X EAPOL state machine logoff
.TP
\fBlogon\fR
IEEE 802.1X EAPOL state machine logon
.TP
\fBset\fR
set variables (shows list of variables when run without arguments)
.TP
\fBpmksa\fR
show PMKSA cache
.TP
\fBreassociate\fR
force reassociation
.TP
\fBreconfigure\fR
force wpa_supplicant to re-read its configuration file
.TP
\fBpreauthenticate <BSSID>\fR
force preauthentication
.TP
\fBidentity <network id> <identity>\fR
configure identity for an SSID
.TP
\fBpassword <network id> <password>\fR
configure password for an SSID
.TP
\fBpin <network id> <pin>\fR
configure pin for an SSID
.TP
\fBotp <network id> <password>\fR
configure one-time-password for an SSID
.TP
\fBbssid *lt;network id> <BSSID>\fR
set preferred BSSID for an SSID
.TP
\fBlist_networks\fR
list configured networks
.TP
\fBterminate\fR
terminate \fBwpa_supplicant\fR
.TP
\fBquit\fR
exit wpa_cli
.SH "SEE ALSO"
.PP
\fBwpa_supplicant\fR(8)
.SH "LEGAL"
.PP
wpa_supplicant is copyright (c) 2003-2005,
Jouni Malinen <jkmaline@cc.hut.fi> and
contributors.
All Rights Reserved.
.PP
This program is dual-licensed under both the GPL version 2
and BSD license. Either license may be used at your option.

View file

@ -0,0 +1,330 @@
<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
<refentry>
<refmeta>
<refentrytitle>wpa_cli</refentrytitle>
<manvolnum>8</manvolnum>
</refmeta>
<refnamediv>
<refname>wpa_cli</refname>
<refpurpose>WPA command line client</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>wpa_cli</command>
<arg>-p <replaceable>path to ctrl sockets</replaceable></arg>
<arg>-i <replaceable>ifname</replaceable></arg>
<arg>-hvB</arg>
<arg>-a <replaceable>action file</replaceable></arg>
<arg>-P <replaceable>pid file</replaceable></arg>
<arg><replaceable>command ...</replaceable></arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Overview</title>
<para>wpa_cli is a text-based frontend program for interacting
with wpa_supplicant. It is used to query current status, change
configuration, trigger events, and request interactive user
input.</para>
<para>wpa_cli can show the current authentication status, selected
security mode, dot11 and dot1x MIBs, etc. In addition, it can
configure some variables like EAPOL state machine parameters and
trigger events like reassociation and IEEE 802.1X
logoff/logon. wpa_cli provides a user interface to request
authentication information, like username and password, if these
are not included in the configuration. This can be used to
implement, e.g., one-time-passwords or generic token card
authentication where the authentication is based on a
challenge-response that uses an external device for generating the
response.</para>
<para>The control interface of wpa_supplicant can be configured to
allow non-root user access (ctrl_interface_group in the
configuration file). This makes it possible to run wpa_cli with a
normal user account.</para>
<para>wpa_cli supports two modes: interactive and command
line. Both modes share the same command set and the main
difference is in interactive mode providing access to unsolicited
messages (event messages, username/password requests).</para>
<para>Interactive mode is started when wpa_cli is executed without
including the command as a command line parameter. Commands are
then entered on the wpa_cli prompt. In command line mode, the same
commands are entered as command line arguments for wpa_cli.</para>
</refsect1>
<refsect1>
<title>Interactive authentication parameters request</title>
<para>When wpa_supplicant need authentication parameters, like
username and password, which are not present in the configuration
file, it sends a request message to all attached frontend programs,
e.g., wpa_cli in interactive mode. wpa_cli shows these requests
with "CTRL-REQ-&lt;type&gt;-&lt;id&gt;:&lt;text&gt;"
prefix. &lt;type&gt; is IDENTITY, PASSWORD, or OTP
(one-time-password). &lt;id&gt; is a unique identifier for the
current network. &lt;text&gt; is description of the request. In
case of OTP request, it includes the challenge from the
authentication server.</para>
<para>The reply to these requests can be given with 'identity',
'password', and 'otp' commands. &lt;id&gt; needs to be copied from the
the matching request. 'password' and 'otp' commands can be used
regardless of whether the request was for PASSWORD or OTP. The
main difference between these two commands is that values given
with 'password' are remembered as long as wpa_supplicant is
running whereas values given with 'otp' are used only once and
then forgotten, i.e., wpa_supplicant will ask frontend for a new
value for every use. This can be used to implement
one-time-password lists and generic token card -based
authentication.</para>
<para>Example request for password and a matching reply:</para>
<blockquote><programlisting>
CTRL-REQ-PASSWORD-1:Password needed for SSID foobar
> password 1 mysecretpassword
</programlisting></blockquote>
<para>Example request for generic token card challenge-response:</para>
<blockquote><programlisting>
CTRL-REQ-OTP-2:Challenge 1235663 needed for SSID foobar
> otp 2 9876
</programlisting></blockquote>
</refsect1>
<refsect1>
<title>Command Arguments</title>
<variablelist>
<varlistentry>
<term>-p path</term>
<listitem><para>Change the path where control sockets should
be found.</para></listitem>
</varlistentry>
<varlistentry>
<term>-i ifname</term>
<listitem><para>Specify the interface that is being
configured. By default, choose the first interface found with
a control socket in the socket path.</para></listitem>
</varlistentry>
<varlistentry>
<term>-h</term>
<listitem><para>Help. Show a usage message.</para></listitem>
</varlistentry>
<varlistentry>
<term>-v</term>
<listitem><para>Show version information.</para></listitem>
</varlistentry>
<varlistentry>
<term>-B</term>
<listitem><para>Run as a daemon in the background.</para></listitem>
</varlistentry>
<varlistentry>
<term>-a file</term>
<listitem><para>Run in daemon mode executing the action file
based on events from wpa_supplicant. The specified file will
be executed with the first argument set to interface name and
second to "CONNECT" or "DISCONNECT" depending on the event.
This can be used </para></listitem>
</varlistentry>
<varlistentry>
<term>-P file</term>
<listitem><para>Set the location of the PID
file.</para></listitem>
</varlistentry>
<varlistentry>
<term>command</term>
<listitem><para>Run a command. The available commands are
listed in the next section.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Commands</title>
<para>The following commands are available:</para>
<variablelist>
<varlistentry>
<term>status</term>
<listitem>
<para>get current WPA/EAPOL/EAP status</para>
</listitem>
</varlistentry>
<varlistentry>
<term>mib</term>
<listitem>
<para>get MIB variables (dot1x, dot11)</para>
</listitem>
</varlistentry>
<varlistentry>
<term>help</term>
<listitem>
<para>show this usage help</para>
</listitem>
</varlistentry>
<varlistentry>
<term>interface [ifname]</term>
<listitem>
<para>show interfaces/select interface</para>
</listitem>
</varlistentry>
<varlistentry>
<term>level &lt;debug level&gt;</term>
<listitem>
<para>change debug level</para>
</listitem>
</varlistentry>
<varlistentry>
<term>license</term>
<listitem>
<para>show full wpa_cli license</para>
</listitem>
</varlistentry>
<varlistentry>
<term>logoff</term>
<listitem>
<para>IEEE 802.1X EAPOL state machine logoff</para>
</listitem>
</varlistentry>
<varlistentry>
<term>logon</term>
<listitem>
<para>IEEE 802.1X EAPOL state machine logon</para>
</listitem>
</varlistentry>
<varlistentry>
<term>set</term>
<listitem>
<para>set variables (shows list of variables when run without arguments)</para>
</listitem>
</varlistentry>
<varlistentry>
<term>pmksa</term>
<listitem>
<para>show PMKSA cache</para>
</listitem>
</varlistentry>
<varlistentry>
<term>reassociate</term>
<listitem>
<para>force reassociation</para>
</listitem>
</varlistentry>
<varlistentry>
<term>reconfigure</term>
<listitem>
<para>force wpa_supplicant to re-read its configuration file</para>
</listitem>
</varlistentry>
<varlistentry>
<term>preauthenticate &lt;BSSID&gt;</term>
<listitem>
<para>force preauthentication</para>
</listitem>
</varlistentry>
<varlistentry>
<term>identity &lt;network id&gt; &lt;identity&gt;</term>
<listitem>
<para>configure identity for an SSID</para>
</listitem>
</varlistentry>
<varlistentry>
<term>password &lt;network id&gt; &lt;password&gt;</term>
<listitem>
<para>configure password for an SSID</para>
</listitem>
</varlistentry>
<varlistentry>
<term>pin &lt;network id&gt; &lt;pin&gt;</term>
<listitem>
<para>configure pin for an SSID</para>
</listitem>
</varlistentry>
<varlistentry>
<term>otp &lt;network id&gt; &lt;password&gt;</term>
<listitem>
<para>configure one-time-password for an SSID</para>
</listitem>
</varlistentry>
<varlistentry>
<term>bssid *lt;network id&gt; &lt;BSSID&gt;</term>
<listitem>
<para>set preferred BSSID for an SSID</para>
</listitem>
</varlistentry>
<varlistentry>
<term>list_networks</term>
<listitem>
<para>list configured networks</para>
</listitem>
</varlistentry>
<varlistentry>
<term>terminate</term>
<listitem>
<para>terminate <command>wpa_supplicant</command></para>
</listitem>
</varlistentry>
<varlistentry>
<term>quit</term>
<listitem><para>exit wpa_cli</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>See Also</title>
<para>
<citerefentry>
<refentrytitle>wpa_supplicant</refentrytitle>
<manvolnum>8</manvolnum>
</citerefentry>
</para>
</refsect1>
<refsect1>
<title>Legal</title>
<para>wpa_supplicant is copyright (c) 2003-2005,
Jouni Malinen <email>jkmaline@cc.hut.fi</email> and
contributors.
All Rights Reserved.</para>
<para>This program is dual-licensed under both the GPL version 2
and BSD license. Either license may be used at your option.</para>
</refsect1>
</refentry>

View file

@ -0,0 +1,39 @@
.\" This manpage has been automatically generated by docbook2man
.\" from a DocBook document. This tool can be found at:
.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/>
.\" Please send any bug reports, improvements, comments, patches,
.\" etc. to Steve Cheng <steve@ggi-project.org>.
.TH "WPA_PASSPHRASE" "8" "08 February 2006" "" ""
.SH NAME
wpa_passphrase \- Set WPA passphrase for a SSID
.SH SYNOPSIS
\fBwpa_passphrase\fR [ \fB\fIssid\fB\fR ] [ \fB\fIpassphrase\fB\fR ]
.SH "OVERVIEW"
.PP
\fBwpa_passphrase\fR pre-computes PSK entries for
network configuration blocks of a
\fIwpa_supplicant.conf\fR file.
.SH "OPTIONS"
.TP
\fBssid\fR
The SSID whose passphrase should be derived.
.TP
\fBpassphrase\fR
The passphrase to use. If not included on the command line,
passphrase will be read from standard input.
.SH "SEE ALSO"
.PP
\fBwpa_supplicant.conf\fR(5)
\fBwpa_supplicant\fR(8)
.SH "LEGAL"
.PP
wpa_supplicant is copyright (c) 2003-2005,
Jouni Malinen <jkmaline@cc.hut.fi> and
contributors.
All Rights Reserved.
.PP
This program is dual-licensed under both the GPL version 2
and BSD license. Either license may be used at your option.

View file

@ -0,0 +1,72 @@
<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
<refentry>
<refmeta>
<refentrytitle>wpa_passphrase</refentrytitle>
<manvolnum>8</manvolnum>
</refmeta>
<refnamediv>
<refname>wpa_passphrase</refname>
<refpurpose>Set WPA passphrase for a SSID</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>wpa_passphrase</command>
<arg><replaceable>ssid</replaceable></arg>
<arg><replaceable>passphrase</replaceable></arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Overview</title>
<para><command>wpa_passphrase</command> pre-computes PSK entries for
network configuration blocks of a
<filename>wpa_supplicant.conf</filename> file.</para>
</refsect1>
<refsect1>
<title>Options</title>
<variablelist>
<varlistentry>
<term>ssid</term>
<listitem>
<para>The SSID whose passphrase should be derived.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>passphrase</term>
<listitem>
<para>The passphrase to use. If not included on the command line,
passphrase will be read from standard input.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>See Also</title>
<para>
<citerefentry>
<refentrytitle>wpa_supplicant.conf</refentrytitle>
<manvolnum>5</manvolnum>
</citerefentry>
<citerefentry>
<refentrytitle>wpa_supplicant</refentrytitle>
<manvolnum>8</manvolnum>
</citerefentry>
</para>
</refsect1>
<refsect1>
<title>Legal</title>
<para>wpa_supplicant is copyright (c) 2003-2005,
Jouni Malinen <email>jkmaline@cc.hut.fi</email> and
contributors.
All Rights Reserved.</para>
<para>This program is dual-licensed under both the GPL version 2
and BSD license. Either license may be used at your option.</para>
</refsect1>
</refentry>

View file

@ -0,0 +1,544 @@
.\" This manpage has been automatically generated by docbook2man
.\" from a DocBook document. This tool can be found at:
.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/>
.\" Please send any bug reports, improvements, comments, patches,
.\" etc. to Steve Cheng <steve@ggi-project.org>.
.TH "WPA_SUPPLICANT" "8" "08 February 2006" "" ""
.SH NAME
wpa_supplicant \- Wi-Fi Protected Access client and IEEE 802.1X supplicant
.SH SYNOPSIS
\fBwpa_supplicant\fR [ \fB-BddehLqqvw\fR ] [ \fB-i\fIifname\fB\fR ] [ \fB-c\fIconfig file\fB\fR ] [ \fB-D\fIdriver\fB\fR ]
.SH "OVERVIEW"
.PP
Wireless networks do not require physical access to the network equipment
in the same way as wired networks. This makes it easier for unauthorized
users to passively monitor a network and capture all transmitted frames.
In addition, unauthorized use of the network is much easier. In many cases,
this can happen even without user's explicit knowledge since the wireless
LAN adapter may have been configured to automatically join any available
network.
.PP
Link-layer encryption can be used to provide a layer of security for
wireless networks. The original wireless LAN standard, IEEE 802.11,
included a simple encryption mechanism, WEP. However, that proved to
be flawed in many areas and network protected with WEP cannot be consider
secure. IEEE 802.1X authentication and frequently changed dynamic WEP keys
can be used to improve the network security, but even that has inherited
security issues due to the use of WEP for encryption. Wi-Fi Protected
Access and IEEE 802.11i amendment to the wireless LAN standard introduce
a much improvement mechanism for securing wireless networks. IEEE 802.11i
enabled networks that are using CCMP (encryption mechanism based on strong
cryptographic algorithm AES) can finally be called secure used for
applications which require efficient protection against unauthorized
access.
.PP
\fBwpa_supplicant\fR is an implementation of
the WPA Supplicant component, i.e., the part that runs in the
client stations. It implements WPA key negotiation with a WPA
Authenticator and EAP authentication with Authentication
Server. In addition, it controls the roaming and IEEE 802.11
authentication/association of the wireless LAN driver.
.PP
\fBwpa_supplicant\fR is designed to be a
"daemon" program that runs in the background and acts as the
backend component controlling the wireless
connection. \fBwpa_supplicant\fR supports separate
frontend programs and an example text-based frontend,
\fBwpa_cli\fR, is included with
wpa_supplicant.
.PP
Before wpa_supplicant can do its work, the network interface
must be available. That means that the physical device must be
present and enabled, and the driver for the device must have be
loaded. Note, however, that the '-w' option of the wpa_supplicant
daemon instructs the daemon to continue running and to wait for
the interface to become available. Without the '-w' option, the
daemon will exit immediately if the device is not already
available.
.PP
After \fBwpa_supplicant\fR has configured the
network device, higher level configuration such as DHCP may
proceed. There are a variety of ways to integrate wpa_supplicant
into a machine's networking scripts, a few of which are described
in sections below.
.PP
The following steps are used when associating with an AP
using WPA:
.TP 0.2i
\(bu
\fBwpa_supplicant\fR requests the kernel
driver to scan neighboring BSSes
.TP 0.2i
\(bu
\fBwpa_supplicant\fR selects a BSS based on
its configuration
.TP 0.2i
\(bu
\fBwpa_supplicant\fR requests the kernel
driver to associate with the chosen BSS
.TP 0.2i
\(bu
If WPA-EAP: integrated IEEE 802.1X Supplicant or
external Xsupplicant completes EAP authentication with the
authentication server (proxied by the Authenticator in the
AP)
.TP 0.2i
\(bu
If WPA-EAP: master key is received from the IEEE 802.1X
Supplicant
.TP 0.2i
\(bu
If WPA-PSK: \fBwpa_supplicant\fR uses PSK
as the master session key
.TP 0.2i
\(bu
\fBwpa_supplicant\fR completes WPA 4-Way
Handshake and Group Key Handshake with the Authenticator
(AP)
.TP 0.2i
\(bu
\fBwpa_supplicant\fR configures encryption
keys for unicast and broadcast
.TP 0.2i
\(bu
normal data packets can be transmitted and received
.SH "SUPPORTED FEATURES"
.PP
Supported WPA/IEEE 802.11i features:
.TP 0.2i
\(bu
WPA-PSK ("WPA-Personal")
.TP 0.2i
\(bu
WPA with EAP (e.g., with RADIUS authentication server)
("WPA-Enterprise") Following authentication methods are
supported with an integrate IEEE 802.1X Supplicant:
.RS
.TP 0.2i
\(bu
EAP-TLS
.RE
.RS
.TP 0.2i
\(bu
EAP-PEAP/MSCHAPv2 (both PEAPv0 and PEAPv1)
.TP 0.2i
\(bu
EAP-PEAP/TLS (both PEAPv0 and PEAPv1)
.TP 0.2i
\(bu
EAP-PEAP/GTC (both PEAPv0 and PEAPv1)
.TP 0.2i
\(bu
EAP-PEAP/OTP (both PEAPv0 and PEAPv1)
.TP 0.2i
\(bu
EAP-PEAP/MD5-Challenge (both PEAPv0 and PEAPv1)
.TP 0.2i
\(bu
EAP-TTLS/EAP-MD5-Challenge
.TP 0.2i
\(bu
EAP-TTLS/EAP-GTC
.TP 0.2i
\(bu
EAP-TTLS/EAP-OTP
.TP 0.2i
\(bu
EAP-TTLS/EAP-MSCHAPv2
.TP 0.2i
\(bu
EAP-TTLS/EAP-TLS
.TP 0.2i
\(bu
EAP-TTLS/MSCHAPv2
.TP 0.2i
\(bu
EAP-TTLS/MSCHAP
.TP 0.2i
\(bu
EAP-TTLS/PAP
.TP 0.2i
\(bu
EAP-TTLS/CHAP
.TP 0.2i
\(bu
EAP-SIM
.TP 0.2i
\(bu
EAP-AKA
.TP 0.2i
\(bu
EAP-PSK
.TP 0.2i
\(bu
EAP-PAX
.TP 0.2i
\(bu
LEAP (note: requires special support from
the driver for IEEE 802.11 authentication)
.TP 0.2i
\(bu
(following methods are supported, but since
they do not generate keying material, they cannot be used
with WPA or IEEE 802.1X WEP keying)
.TP 0.2i
\(bu
EAP-MD5-Challenge
.TP 0.2i
\(bu
EAP-MSCHAPv2
.TP 0.2i
\(bu
EAP-GTC
.TP 0.2i
\(bu
EAP-OTP
.RE
.TP 0.2i
\(bu
key management for CCMP, TKIP, WEP104, WEP40
.TP 0.2i
\(bu
RSN/WPA2 (IEEE 802.11i)
.RS
.TP 0.2i
\(bu
pre-authentication
.TP 0.2i
\(bu
PMKSA caching
.RE
.SH "AVAILABLE DRIVERS"
.PP
The available drivers to specify with the -D option are:
.TP
\fBhostap\fR
(default) Host AP driver (Intersil Prism2/2.5/3).
(this can also be used with Linuxant DriverLoader).
.TP
\fBhermes\fR
Agere Systems Inc. driver (Hermes-I/Hermes-II).
.TP
\fBmadwifi\fR
MADWIFI 802.11 support (Atheros, etc.).
.TP
\fBatmel\fR
ATMEL AT76C5XXx (USB, PCMCIA).
.TP
\fBwext\fR
Linux wireless extensions (generic).
.TP
\fBndiswrapper\fR
Linux ndiswrapper.
.TP
\fBbroadcom\fR
Broadcom wl.o driver.
.TP
\fBipw\fR
Intel ipw2100/2200 driver.
.TP
\fBwired\fR
wpa_supplicant wired Ethernet driver
.TP
\fBbsd\fR
BSD 802.11 support (Atheros, etc.).
.TP
\fBndis\fR
Windows NDIS driver.
.SH "COMMAND LINE OPTIONS"
.TP
\fB-B\fR
Run daemon in the background.
.TP
\fB-i ifname\fR
Interface to listen on.
.TP
\fB-c filename\fR
Path to configuration file.
.TP
\fB-D driver\fR
Driver to use. See the available options below.
.TP
\fB-d\fR
Increase debugging verbosity (-dd even more).
.TP
\fB-K\fR
Include keys (passwords, etc.) in debug output.
.TP
\fB-t\fR
Include timestamp in debug messages.
.TP
\fB-e\fR
Use external IEEE 802.1X Supplicant (e.g.,
\fBxsupplicant\fR) (this disables the internal
Supplicant).
.TP
\fB-h\fR
Help. Show a usage message.
.TP
\fB-L\fR
Show license (GPL and BSD).
.TP
\fB-q\fR
Decrease debugging verbosity (-qq even less).
.TP
\fB-v\fR
Show version.
.TP
\fB-w\fR
wait for interface to be added, if needed. normally,
\fBwpa_supplicant\fR will exit if the interface
is not there yet.
.TP
\fB-N\fR
Start describing new interface.
.SH "EXAMPLES"
.PP
In most common cases, \fBwpa_supplicant\fR is
started with:
.sp
.RS
.nf
wpa_supplicant -Bw -c/etc/wpa_supplicant.conf -iwlan0
.fi
.RE
.PP
This makes the process fork into background and wait for the wlan0
interface if it is not available at startup time.
.PP
The easiest way to debug problems, and to get debug log for
bug reports, is to start \fBwpa_supplicant\fR on
foreground with debugging enabled:
.sp
.RS
.nf
wpa_supplicant -c/etc/wpa_supplicant.conf -iwlan0 -d
.fi
.RE
.PP
\fBwpa_supplicant\fR can control multiple
interfaces (radios) either by running one process for each
interface separately or by running just one process and list of
options at command line. Each interface is separated with -N
argument. As an example, following command would start
wpa_supplicant for two interfaces:
.sp
.RS
.nf
wpa_supplicant \\
-c wpa1.conf -i wlan0 -D hostap -N \\
-c wpa2.conf -i ath0 -D madwifi
.fi
.RE
.SH "OS REQUIREMENTS"
.PP
Current hardware/software requirements:
.TP 0.2i
\(bu
Linux kernel 2.4.x or 2.6.x with Linux Wireless
Extensions v15 or newer
.TP 0.2i
\(bu
FreeBSD 6-CURRENT
.TP 0.2i
\(bu
Microsoft Windows with WinPcap (at least WinXP, may work
with other versions)
.SH "SUPPORTED DRIVERS"
.TP
\fBHost AP driver for Prism2/2.5/3 (development snapshot/v0.2.x)\fR
(http://hostap.epitest.fi/) Driver needs to be set in
Managed mode ('iwconfig wlan0 mode managed'). Please note
that station firmware version needs to be 1.7.0 or newer to
work in WPA mode.
.TP
\fBLinuxant DriverLoader\fR
(http://www.linuxant.com/driverloader/)
with Windows NDIS driver for your wlan card supporting WPA.
.TP
\fBAgere Systems Inc. Linux Driver\fR
(http://www.agere.com/support/drivers/) Please note
that the driver interface file (driver_hermes.c) and hardware
specific include files are not included in the wpa_supplicant
distribution. You will need to copy these from the source
package of the Agere driver.
.TP
\fBmadwifi driver for cards based on Atheros chip set (ar521x)\fR
(http://sourceforge.net/projects/madwifi/) Please
note that you will need to modify the wpa_supplicant .config
file to use the correct path for the madwifi driver root
directory (CFLAGS += -I../madwifi/wpa line in example
defconfig).
.TP
\fBATMEL AT76C5XXx driver for USB and PCMCIA cards\fR
(http://atmelwlandriver.sourceforge.net/).
.TP
\fBLinux ndiswrapper\fR
(http://ndiswrapper.sourceforge.net/) with Windows
NDIS driver.
.TP
\fBBroadcom wl.o driver\fR
This is a generic Linux driver for Broadcom IEEE
802.11a/g cards. However, it is proprietary driver that is
not publicly available except for couple of exceptions, mainly
Broadcom-based APs/wireless routers that use Linux. The driver
binary can be downloaded, e.g., from Linksys support site
(http://www.linksys.com/support/gpl.asp) for Linksys
WRT54G. The GPL tarball includes cross-compiler and the needed
header file, wlioctl.h, for compiling wpa_supplicant. This
driver support in wpa_supplicant is expected to work also with
other devices based on Broadcom driver (assuming the driver
includes client mode support).
.TP
\fB Intel ipw2100 driver\fR
(http://sourceforge.net/projects/ipw2100/)
.TP
\fBIntel ipw2200 driver\fR
(http://sourceforge.net/projects/ipw2200/)
.TP
\fBLinux wireless extensions\fR
In theory, any driver that supports Linux wireless
extensions can be used with IEEE 802.1X (i.e., not WPA) when
using ap_scan=0 option in configuration file.
.TP
\fBWired Ethernet drivers\fR
Use ap_scan=0.
.TP
\fBBSD net80211 layer (e.g., Atheros driver)\fR
At the moment, this is for FreeBSD 6-CURRENT branch.
.TP
\fBWindows NDIS\fR
The current Windows port requires WinPcap
(http://winpcap.polito.it/). See README-Windows.txt for more
information.
.PP
wpa_supplicant was designed to be portable for different
drivers and operating systems. Hopefully, support for more wlan
cards and OSes will be added in the future. See developer.txt for
more information about the design of wpa_supplicant and porting to
other drivers. One main goal is to add full WPA/WPA2 support to
Linux wireless extensions to allow new drivers to be supported
without having to implement new driver-specific interface code in
wpa_supplicant.
.SH "ARCHITECTURE"
.PP
The
\fBwpa_supplicant\fR system consists of the following
components:
.TP
\fB\fIwpa_supplicant.conf\fB \fR
the configuration file describing all networks that the
user wants the computer to connect to.
.TP
\fBwpa_supplicant\fR
the program that directly interacts with the
network interface.
.TP
\fBwpa_cli\fR
the
client program that provides a high-level interface to the
functionality of the daemon.
.TP
\fBwpa_passphrase\fR
a utility needed to construct
\fIwpa_supplicant.conf\fR files that include
encrypted passwords.
.SH "QUICK START"
.PP
First, make a configuration file, e.g.
\fI/etc/wpa_supplicant.conf\fR, that describes the networks
you are interested in. See \fBwpa_supplicant\fR(5)
for details.
.PP
Once the configuration is ready, you can test whether the
configuration works by running \fBwpa_supplicant\fR
with following command to start it on foreground with debugging
enabled:
.sp
.RS
.nf
wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -d
.fi
.RE
.PP
Assuming everything goes fine, you can start using following
command to start \fBwpa_supplicant\fR on background
without debugging:
.sp
.RS
.nf
wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -B
.fi
.RE
.PP
Please note that if you included more than one driver
interface in the build time configuration (.config), you may need
to specify which interface to use by including -D<driver
name> option on the command line.
.SH "INTERFACE TO PCMCIA-CS/CARDMRG"
.PP
For example, following small changes to pcmcia-cs scripts
can be used to enable WPA support:
.PP
Add MODE="Managed" and WPA="y" to the network scheme in
\fI/etc/pcmcia/wireless.opts\fR\&.
.PP
Add the following block to the end of 'start' action handler
in \fI/etc/pcmcia/wireless\fR:
.sp
.RS
.nf
if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then
/usr/local/bin/wpa_supplicant -Bw -c/etc/wpa_supplicant.conf -i$DEVICE
fi
.fi
.RE
.PP
Add the following block to the end of 'stop' action handler
(may need to be separated from other actions) in
\fI/etc/pcmcia/wireless\fR:
.sp
.RS
.nf
if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then
killall wpa_supplicant
fi
.fi
.RE
.PP
This will make \fBcardmgr\fR start
\fBwpa_supplicant\fR when the card is plugged
in. \fBwpa_supplicant\fR will wait until the
interface is set up--either when a static IP address is configured
or when DHCP client is started--and will then negotiate keys with
the AP.
.SH "SEE ALSO"
.PP
\fBwpa_background\fR(8)
\fBwpa_supplicant.conf\fR(5)
\fBwpa_cli\fR(8)
\fBwpa_passphrase\fR(8)
.SH "LEGAL"
.PP
wpa_supplicant is copyright (c) 2003-2005,
Jouni Malinen <jkmaline@cc.hut.fi> and
contributors.
All Rights Reserved.
.PP
This program is dual-licensed under both the GPL version 2
and BSD license. Either license may be used at your option.

View file

@ -0,0 +1,230 @@
.\" This manpage has been automatically generated by docbook2man
.\" from a DocBook document. This tool can be found at:
.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/>
.\" Please send any bug reports, improvements, comments, patches,
.\" etc. to Steve Cheng <steve@ggi-project.org>.
.TH "WPA_SUPPLICANT.CONF" "5" "08 February 2006" "" ""
.SH NAME
wpa_supplicant.conf \- configuration file for wpa_supplicant
.SH "OVERVIEW"
.PP
\fBwpa_supplicant\fR is configured using a text
file that lists all accepted networks and security policies,
including pre-shared keys. See the example configuration file,
probably in \fB/usr/share/doc/wpa_supplicant/\fR, for
detailed information about the configuration format and supported
fields.
.PP
All file paths in this configuration file should use full
(absolute, not relative to working directory) path in order to allow
working directory to be changed. This can happen if wpa_supplicant is
run in the background.
.PP
Changes to configuration file can be reloaded be sending
SIGHUP signal to \fBwpa_supplicant\fR ('killall -HUP
wpa_supplicant'). Similarly, reloading can be triggered with
'wpa_cli reconfigure' command.
.PP
Configuration file can include one or more network blocks,
e.g., one for each used SSID. wpa_supplicant will automatically
select the best betwork based on the order of network blocks in
the configuration file, network security level (WPA/WPA2 is
prefered), and signal strength.
.SH "QUICK EXAMPLES"
.TP 3
1.
WPA-Personal (PSK) as home network and WPA-Enterprise with
EAP-TLS as work network.
.sp
.RS
.nf
# allow frontend (e.g., wpa_cli) to be used by all users in 'wheel' group
ctrl_interface=/var/run/wpa_supplicant
ctrl_interface_group=wheel
#
# home network; allow all valid ciphers
network={
ssid="home"
scan_ssid=1
key_mgmt=WPA-PSK
psk="very secret passphrase"
}
#
# work network; use EAP-TLS with WPA; allow only CCMP and TKIP ciphers
network={
ssid="work"
scan_ssid=1
key_mgmt=WPA-EAP
pairwise=CCMP TKIP
group=CCMP TKIP
eap=TLS
identity="user@example.com"
ca_cert="/etc/cert/ca.pem"
client_cert="/etc/cert/user.pem"
private_key="/etc/cert/user.prv"
private_key_passwd="password"
}
.fi
.RE
.TP 3
2.
WPA-RADIUS/EAP-PEAP/MSCHAPv2 with RADIUS servers that
use old peaplabel (e.g., Funk Odyssey and SBR, Meetinghouse
Aegis, Interlink RAD-Series)
.sp
.RS
.nf
ctrl_interface=/var/run/wpa_supplicant
ctrl_interface_group=wheel
network={
ssid="example"
scan_ssid=1
key_mgmt=WPA-EAP
eap=PEAP
identity="user@example.com"
password="foobar"
ca_cert="/etc/cert/ca.pem"
phase1="peaplabel=0"
phase2="auth=MSCHAPV2"
}
.fi
.RE
.TP 3
3.
EAP-TTLS/EAP-MD5-Challenge configuration with anonymous
identity for the unencrypted use. Real identity is sent only
within an encrypted TLS tunnel.
.sp
.RS
.nf
ctrl_interface=/var/run/wpa_supplicant
ctrl_interface_group=wheel
network={
ssid="example"
scan_ssid=1
key_mgmt=WPA-EAP
eap=TTLS
identity="user@example.com"
anonymous_identity="anonymous@example.com"
password="foobar"
ca_cert="/etc/cert/ca.pem"
phase2="auth=MD5"
}
.fi
.RE
.TP 3
4.
IEEE 802.1X (i.e., no WPA) with dynamic WEP keys
(require both unicast and broadcast); use EAP-TLS for
authentication
.sp
.RS
.nf
ctrl_interface=/var/run/wpa_supplicant
ctrl_interface_group=wheel
network={
ssid="1x-test"
scan_ssid=1
key_mgmt=IEEE8021X
eap=TLS
identity="user@example.com"
ca_cert="/etc/cert/ca.pem"
client_cert="/etc/cert/user.pem"
private_key="/etc/cert/user.prv"
private_key_passwd="password"
eapol_flags=3
}
.fi
.RE
.TP 3
5.
Catch all example that allows more or less all
configuration modes. The configuration options are used based
on what security policy is used in the selected SSID. This is
mostly for testing and is not recommended for normal
use.
.sp
.RS
.nf
ctrl_interface=/var/run/wpa_supplicant
ctrl_interface_group=wheel
network={
ssid="example"
scan_ssid=1
key_mgmt=WPA-EAP WPA-PSK IEEE8021X NONE
pairwise=CCMP TKIP
group=CCMP TKIP WEP104 WEP40
psk="very secret passphrase"
eap=TTLS PEAP TLS
identity="user@example.com"
password="foobar"
ca_cert="/etc/cert/ca.pem"
client_cert="/etc/cert/user.pem"
private_key="/etc/cert/user.prv"
private_key_passwd="password"
phase1="peaplabel=0"
ca_cert2="/etc/cert/ca2.pem"
client_cert2="/etc/cer/user.pem"
private_key2="/etc/cer/user.prv"
private_key2_passwd="password"
}
.fi
.RE
.TP 3
6.
Authentication for wired Ethernet. This can be used with
'wired' interface (-Dwired on command line).
.sp
.RS
.nf
ctrl_interface=/var/run/wpa_supplicant
ctrl_interface_group=wheel
ap_scan=0
network={
key_mgmt=IEEE8021X
eap=MD5
identity="user"
password="password"
eapol_flags=0
}
.fi
.RE
.SH "CERTIFICATES"
.PP
Some EAP authentication methods require use of
certificates. EAP-TLS uses both server side and client
certificates whereas EAP-PEAP and EAP-TTLS only require the server
side certificate. When client certificate is used, a matching
private key file has to also be included in configuration. If the
private key uses a passphrase, this has to be configured in
wpa_supplicant.conf ("private_key_passwd").
.PP
wpa_supplicant supports X.509 certificates in PEM and DER
formats. User certificate and private key can be included in the
same file.
.PP
If the user certificate and private key is received in
PKCS#12/PFX format, they need to be converted to suitable PEM/DER
format for wpa_supplicant. This can be done, e.g., with following
commands:
.sp
.RS
.nf
# convert client certificate and private key to PEM format
openssl pkcs12 -in example.pfx -out user.pem -clcerts
# convert CA certificate (if included in PFX file) to PEM format
openssl pkcs12 -in example.pfx -out ca.pem -cacerts -nokeys
.fi
.RE
.SH "SEE ALSO"
.PP
\fBwpa_supplicant\fR(8)
\fBopenssl\fR(1)

View file

@ -0,0 +1,244 @@
<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
<refentry>
<refmeta>
<refentrytitle>wpa_supplicant.conf</refentrytitle>
<manvolnum>5</manvolnum>
</refmeta>
<refnamediv>
<refname>wpa_supplicant.conf</refname>
<refpurpose>configuration file for wpa_supplicant</refpurpose>
</refnamediv>
<refsect1>
<title>Overview</title>
<para><command>wpa_supplicant</command> is configured using a text
file that lists all accepted networks and security policies,
including pre-shared keys. See the example configuration file,
probably in <command>/usr/share/doc/wpa_supplicant/</command>, for
detailed information about the configuration format and supported
fields.</para>
<para>All file paths in this configuration file should use full
(absolute, not relative to working directory) path in order to allow
working directory to be changed. This can happen if wpa_supplicant is
run in the background.</para>
<para>Changes to configuration file can be reloaded be sending
SIGHUP signal to <command>wpa_supplicant</command> ('killall -HUP
wpa_supplicant'). Similarly, reloading can be triggered with
'wpa_cli reconfigure' command.</para>
<para>Configuration file can include one or more network blocks,
e.g., one for each used SSID. wpa_supplicant will automatically
select the best betwork based on the order of network blocks in
the configuration file, network security level (WPA/WPA2 is
prefered), and signal strength.</para>
</refsect1>
<refsect1>
<title>Quick Examples</title>
<orderedlist>
<listitem>
<para>WPA-Personal (PSK) as home network and WPA-Enterprise with
EAP-TLS as work network.</para>
<blockquote><programlisting>
# allow frontend (e.g., wpa_cli) to be used by all users in 'wheel' group
ctrl_interface=/var/run/wpa_supplicant
ctrl_interface_group=wheel
#
# home network; allow all valid ciphers
network={
ssid="home"
scan_ssid=1
key_mgmt=WPA-PSK
psk="very secret passphrase"
}
#
# work network; use EAP-TLS with WPA; allow only CCMP and TKIP ciphers
network={
ssid="work"
scan_ssid=1
key_mgmt=WPA-EAP
pairwise=CCMP TKIP
group=CCMP TKIP
eap=TLS
identity="user@example.com"
ca_cert="/etc/cert/ca.pem"
client_cert="/etc/cert/user.pem"
private_key="/etc/cert/user.prv"
private_key_passwd="password"
}
</programlisting></blockquote>
</listitem>
<listitem>
<para>WPA-RADIUS/EAP-PEAP/MSCHAPv2 with RADIUS servers that
use old peaplabel (e.g., Funk Odyssey and SBR, Meetinghouse
Aegis, Interlink RAD-Series)</para>
<blockquote><programlisting>
ctrl_interface=/var/run/wpa_supplicant
ctrl_interface_group=wheel
network={
ssid="example"
scan_ssid=1
key_mgmt=WPA-EAP
eap=PEAP
identity="user@example.com"
password="foobar"
ca_cert="/etc/cert/ca.pem"
phase1="peaplabel=0"
phase2="auth=MSCHAPV2"
}
</programlisting></blockquote>
</listitem>
<listitem>
<para>EAP-TTLS/EAP-MD5-Challenge configuration with anonymous
identity for the unencrypted use. Real identity is sent only
within an encrypted TLS tunnel.</para>
<blockquote><programlisting>
ctrl_interface=/var/run/wpa_supplicant
ctrl_interface_group=wheel
network={
ssid="example"
scan_ssid=1
key_mgmt=WPA-EAP
eap=TTLS
identity="user@example.com"
anonymous_identity="anonymous@example.com"
password="foobar"
ca_cert="/etc/cert/ca.pem"
phase2="auth=MD5"
}
</programlisting></blockquote>
</listitem>
<listitem>
<para>IEEE 802.1X (i.e., no WPA) with dynamic WEP keys
(require both unicast and broadcast); use EAP-TLS for
authentication</para>
<blockquote><programlisting>
ctrl_interface=/var/run/wpa_supplicant
ctrl_interface_group=wheel
network={
ssid="1x-test"
scan_ssid=1
key_mgmt=IEEE8021X
eap=TLS
identity="user@example.com"
ca_cert="/etc/cert/ca.pem"
client_cert="/etc/cert/user.pem"
private_key="/etc/cert/user.prv"
private_key_passwd="password"
eapol_flags=3
}
</programlisting></blockquote>
</listitem>
<listitem>
<para>Catch all example that allows more or less all
configuration modes. The configuration options are used based
on what security policy is used in the selected SSID. This is
mostly for testing and is not recommended for normal
use.</para>
<blockquote><programlisting>
ctrl_interface=/var/run/wpa_supplicant
ctrl_interface_group=wheel
network={
ssid="example"
scan_ssid=1
key_mgmt=WPA-EAP WPA-PSK IEEE8021X NONE
pairwise=CCMP TKIP
group=CCMP TKIP WEP104 WEP40
psk="very secret passphrase"
eap=TTLS PEAP TLS
identity="user@example.com"
password="foobar"
ca_cert="/etc/cert/ca.pem"
client_cert="/etc/cert/user.pem"
private_key="/etc/cert/user.prv"
private_key_passwd="password"
phase1="peaplabel=0"
ca_cert2="/etc/cert/ca2.pem"
client_cert2="/etc/cer/user.pem"
private_key2="/etc/cer/user.prv"
private_key2_passwd="password"
}
</programlisting></blockquote>
</listitem>
<listitem>
<para>Authentication for wired Ethernet. This can be used with
'wired' interface (-Dwired on command line).</para>
<blockquote><programlisting>
ctrl_interface=/var/run/wpa_supplicant
ctrl_interface_group=wheel
ap_scan=0
network={
key_mgmt=IEEE8021X
eap=MD5
identity="user"
password="password"
eapol_flags=0
}
</programlisting></blockquote>
</listitem>
</orderedlist>
</refsect1>
<refsect1>
<title>Certificates</title>
<para>Some EAP authentication methods require use of
certificates. EAP-TLS uses both server side and client
certificates whereas EAP-PEAP and EAP-TTLS only require the server
side certificate. When client certificate is used, a matching
private key file has to also be included in configuration. If the
private key uses a passphrase, this has to be configured in
wpa_supplicant.conf ("private_key_passwd").</para>
<para>wpa_supplicant supports X.509 certificates in PEM and DER
formats. User certificate and private key can be included in the
same file.</para>
<para>If the user certificate and private key is received in
PKCS#12/PFX format, they need to be converted to suitable PEM/DER
format for wpa_supplicant. This can be done, e.g., with following
commands:</para>
<blockquote><programlisting>
# convert client certificate and private key to PEM format
openssl pkcs12 -in example.pfx -out user.pem -clcerts
# convert CA certificate (if included in PFX file) to PEM format
openssl pkcs12 -in example.pfx -out ca.pem -cacerts -nokeys
</programlisting></blockquote>
</refsect1>
<refsect1>
<title>See Also</title>
<para>
<citerefentry>
<refentrytitle>wpa_supplicant</refentrytitle>
<manvolnum>8</manvolnum>
</citerefentry>
<citerefentry>
<refentrytitle>openssl</refentrytitle>
<manvolnum>1</manvolnum>
</citerefentry>
</para>
</refsect1>
</refentry>

View file

@ -0,0 +1,761 @@
<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
<refentry>
<refmeta>
<refentrytitle>wpa_supplicant</refentrytitle>
<manvolnum>8</manvolnum>
</refmeta>
<refnamediv>
<refname>wpa_supplicant</refname>
<refpurpose>Wi-Fi Protected Access client and IEEE 802.1X supplicant</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>wpa_supplicant</command>
<arg>-BddehLqqvw</arg>
<arg>-i<replaceable>ifname</replaceable></arg>
<arg>-c<replaceable>config file</replaceable></arg>
<arg>-D<replaceable>driver</replaceable></arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Overview</title>
<para>
Wireless networks do not require physical access to the network equipment
in the same way as wired networks. This makes it easier for unauthorized
users to passively monitor a network and capture all transmitted frames.
In addition, unauthorized use of the network is much easier. In many cases,
this can happen even without user's explicit knowledge since the wireless
LAN adapter may have been configured to automatically join any available
network.
</para>
<para>
Link-layer encryption can be used to provide a layer of security for
wireless networks. The original wireless LAN standard, IEEE 802.11,
included a simple encryption mechanism, WEP. However, that proved to
be flawed in many areas and network protected with WEP cannot be consider
secure. IEEE 802.1X authentication and frequently changed dynamic WEP keys
can be used to improve the network security, but even that has inherited
security issues due to the use of WEP for encryption. Wi-Fi Protected
Access and IEEE 802.11i amendment to the wireless LAN standard introduce
a much improvement mechanism for securing wireless networks. IEEE 802.11i
enabled networks that are using CCMP (encryption mechanism based on strong
cryptographic algorithm AES) can finally be called secure used for
applications which require efficient protection against unauthorized
access.
</para>
<para><command>wpa_supplicant</command> is an implementation of
the WPA Supplicant component, i.e., the part that runs in the
client stations. It implements WPA key negotiation with a WPA
Authenticator and EAP authentication with Authentication
Server. In addition, it controls the roaming and IEEE 802.11
authentication/association of the wireless LAN driver.</para>
<para><command>wpa_supplicant</command> is designed to be a
"daemon" program that runs in the background and acts as the
backend component controlling the wireless
connection. <command>wpa_supplicant</command> supports separate
frontend programs and an example text-based frontend,
<command>wpa_cli</command>, is included with
wpa_supplicant.</para>
<para>Before wpa_supplicant can do its work, the network interface
must be available. That means that the physical device must be
present and enabled, and the driver for the device must have be
loaded. Note, however, that the '-w' option of the wpa_supplicant
daemon instructs the daemon to continue running and to wait for
the interface to become available. Without the '-w' option, the
daemon will exit immediately if the device is not already
available.</para>
<para>After <command>wpa_supplicant</command> has configured the
network device, higher level configuration such as DHCP may
proceed. There are a variety of ways to integrate wpa_supplicant
into a machine's networking scripts, a few of which are described
in sections below.</para>
<para>The following steps are used when associating with an AP
using WPA:</para>
<itemizedlist>
<listitem>
<para><command>wpa_supplicant</command> requests the kernel
driver to scan neighboring BSSes</para>
</listitem>
<listitem>
<para><command>wpa_supplicant</command> selects a BSS based on
its configuration</para>
</listitem>
<listitem>
<para><command>wpa_supplicant</command> requests the kernel
driver to associate with the chosen BSS</para>
</listitem>
<listitem>
<para>If WPA-EAP: integrated IEEE 802.1X Supplicant or
external Xsupplicant completes EAP authentication with the
authentication server (proxied by the Authenticator in the
AP)</para>
</listitem>
<listitem>
<para>If WPA-EAP: master key is received from the IEEE 802.1X
Supplicant</para>
</listitem>
<listitem>
<para>If WPA-PSK: <command>wpa_supplicant</command> uses PSK
as the master session key</para>
</listitem>
<listitem>
<para><command>wpa_supplicant</command> completes WPA 4-Way
Handshake and Group Key Handshake with the Authenticator
(AP)</para>
</listitem>
<listitem>
<para><command>wpa_supplicant</command> configures encryption
keys for unicast and broadcast</para>
</listitem>
<listitem>
<para>normal data packets can be transmitted and received</para>
</listitem>
</itemizedlist>
</refsect1>
<refsect1>
<title>Supported Features</title>
<para>Supported WPA/IEEE 802.11i features:</para>
<itemizedlist>
<listitem>
<para>WPA-PSK ("WPA-Personal")</para>
</listitem>
<listitem>
<para>WPA with EAP (e.g., with RADIUS authentication server)
("WPA-Enterprise") Following authentication methods are
supported with an integrate IEEE 802.1X Supplicant:</para>
<itemizedlist>
<listitem>
<para>EAP-TLS</para>
</listitem>
</itemizedlist>
<itemizedlist>
<listitem>
<para>EAP-PEAP/MSCHAPv2 (both PEAPv0 and PEAPv1)</para>
</listitem>
<listitem>
<para>EAP-PEAP/TLS (both PEAPv0 and PEAPv1)</para>
</listitem>
<listitem>
<para>EAP-PEAP/GTC (both PEAPv0 and PEAPv1)</para>
</listitem>
<listitem>
<para>EAP-PEAP/OTP (both PEAPv0 and PEAPv1)</para>
</listitem>
<listitem>
<para>EAP-PEAP/MD5-Challenge (both PEAPv0 and PEAPv1)</para>
</listitem>
<listitem>
<para>EAP-TTLS/EAP-MD5-Challenge</para>
</listitem>
<listitem>
<para>EAP-TTLS/EAP-GTC</para>
</listitem>
<listitem><para>EAP-TTLS/EAP-OTP</para></listitem>
<listitem><para>EAP-TTLS/EAP-MSCHAPv2</para></listitem>
<listitem><para>EAP-TTLS/EAP-TLS</para></listitem>
<listitem><para>EAP-TTLS/MSCHAPv2</para></listitem>
<listitem><para>EAP-TTLS/MSCHAP</para></listitem>
<listitem><para>EAP-TTLS/PAP</para></listitem>
<listitem><para>EAP-TTLS/CHAP</para></listitem>
<listitem><para>EAP-SIM</para></listitem>
<listitem><para>EAP-AKA</para></listitem>
<listitem><para>EAP-PSK</para></listitem>
<listitem><para>EAP-PAX</para></listitem>
<listitem><para>LEAP (note: requires special support from
the driver for IEEE 802.11 authentication)</para></listitem>
<listitem><para>(following methods are supported, but since
they do not generate keying material, they cannot be used
with WPA or IEEE 802.1X WEP keying)</para></listitem>
<listitem><para>EAP-MD5-Challenge </para></listitem>
<listitem><para>EAP-MSCHAPv2</para></listitem>
<listitem><para>EAP-GTC</para></listitem>
<listitem><para>EAP-OTP</para></listitem>
</itemizedlist>
</listitem>
<listitem>
<para>key management for CCMP, TKIP, WEP104, WEP40</para>
</listitem>
<listitem>
<para>RSN/WPA2 (IEEE 802.11i)</para>
<itemizedlist>
<listitem>
<para>pre-authentication</para>
</listitem>
<listitem>
<para>PMKSA caching</para>
</listitem>
</itemizedlist>
</listitem>
</itemizedlist>
</refsect1>
<refsect1>
<title>Available Drivers</title>
<para>The available drivers to specify with the -D option are:</para>
<variablelist>
<varlistentry>
<term>hostap</term>
<listitem>
<para>(default) Host AP driver (Intersil Prism2/2.5/3).
(this can also be used with Linuxant DriverLoader).</para>
</listitem>
</varlistentry>
<varlistentry>
<term>hermes</term>
<listitem>
<para>Agere Systems Inc. driver (Hermes-I/Hermes-II).</para>
</listitem>
</varlistentry>
<varlistentry>
<term>madwifi</term>
<listitem>
<para>MADWIFI 802.11 support (Atheros, etc.).</para>
</listitem>
</varlistentry>
<varlistentry>
<term>atmel</term>
<listitem>
<para>ATMEL AT76C5XXx (USB, PCMCIA).</para>
</listitem>
</varlistentry>
<varlistentry>
<term>wext</term>
<listitem>
<para>Linux wireless extensions (generic).</para>
</listitem>
</varlistentry>
<varlistentry>
<term>ndiswrapper</term>
<listitem>
<para>Linux ndiswrapper.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>broadcom</term>
<listitem>
<para>Broadcom wl.o driver.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>ipw</term>
<listitem>
<para>Intel ipw2100/2200 driver.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>wired</term>
<listitem>
<para>wpa_supplicant wired Ethernet driver</para>
</listitem>
</varlistentry>
<varlistentry>
<term>bsd</term>
<listitem>
<para>BSD 802.11 support (Atheros, etc.).</para>
</listitem>
</varlistentry>
<varlistentry>
<term>ndis</term>
<listitem>
<para>Windows NDIS driver.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Command Line Options</title>
<variablelist>
<varlistentry>
<term>-B</term>
<listitem>
<para>Run daemon in the background.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-i ifname</term>
<listitem>
<para>Interface to listen on.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-c filename</term>
<listitem>
<para>Path to configuration file.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-D driver</term>
<listitem>
<para>Driver to use. See the available options below.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-d</term>
<listitem>
<para>Increase debugging verbosity (-dd even more).</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-K</term>
<listitem>
<para>Include keys (passwords, etc.) in debug output.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-t</term>
<listitem>
<para>Include timestamp in debug messages.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-e</term>
<listitem>
<para>Use external IEEE 802.1X Supplicant (e.g.,
<command>xsupplicant</command>) (this disables the internal
Supplicant).</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-h</term>
<listitem>
<para>Help. Show a usage message.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-L</term>
<listitem>
<para>Show license (GPL and BSD).</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-q</term>
<listitem>
<para>Decrease debugging verbosity (-qq even less).</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-v</term>
<listitem>
<para>Show version.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-w</term>
<listitem>
<para>wait for interface to be added, if needed. normally,
<command>wpa_supplicant</command> will exit if the interface
is not there yet.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-N</term>
<listitem>
<para>Start describing new interface.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Examples</title>
<para>In most common cases, <command>wpa_supplicant</command> is
started with:</para>
<blockquote><programlisting>
wpa_supplicant -Bw -c/etc/wpa_supplicant.conf -iwlan0
</programlisting></blockquote>
<para>This makes the process fork into background and wait for the wlan0
interface if it is not available at startup time.</para>
<para>The easiest way to debug problems, and to get debug log for
bug reports, is to start <command>wpa_supplicant</command> on
foreground with debugging enabled:</para>
<blockquote><programlisting>
wpa_supplicant -c/etc/wpa_supplicant.conf -iwlan0 -d
</programlisting></blockquote>
<para><command>wpa_supplicant</command> can control multiple
interfaces (radios) either by running one process for each
interface separately or by running just one process and list of
options at command line. Each interface is separated with -N
argument. As an example, following command would start
wpa_supplicant for two interfaces:</para>
<blockquote><programlisting>
wpa_supplicant \
-c wpa1.conf -i wlan0 -D hostap -N \
-c wpa2.conf -i ath0 -D madwifi
</programlisting></blockquote>
</refsect1>
<refsect1>
<title>OS Requirements</title>
<para>Current hardware/software requirements:</para>
<itemizedlist>
<listitem>
<para>Linux kernel 2.4.x or 2.6.x with Linux Wireless
Extensions v15 or newer</para>
</listitem>
<listitem>
<para>FreeBSD 6-CURRENT</para>
</listitem>
<listitem>
<para>Microsoft Windows with WinPcap (at least WinXP, may work
with other versions)</para>
</listitem>
</itemizedlist>
</refsect1>
<refsect1>
<title>Supported Drivers</title>
<variablelist>
<varlistentry>
<term>Host AP driver for Prism2/2.5/3 (development
snapshot/v0.2.x)</term>
<listitem>
<para> (http://hostap.epitest.fi/) Driver needs to be set in
Managed mode ('iwconfig wlan0 mode managed'). Please note
that station firmware version needs to be 1.7.0 or newer to
work in WPA mode.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Linuxant DriverLoader</term>
<listitem>
<para>(http://www.linuxant.com/driverloader/)
with Windows NDIS driver for your wlan card supporting WPA.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Agere Systems Inc. Linux Driver</term>
<listitem>
<para> (http://www.agere.com/support/drivers/) Please note
that the driver interface file (driver_hermes.c) and hardware
specific include files are not included in the wpa_supplicant
distribution. You will need to copy these from the source
package of the Agere driver.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>madwifi driver for cards based on Atheros chip set (ar521x)</term>
<listitem>
<para> (http://sourceforge.net/projects/madwifi/) Please
note that you will need to modify the wpa_supplicant .config
file to use the correct path for the madwifi driver root
directory (CFLAGS += -I../madwifi/wpa line in example
defconfig).</para>
</listitem>
</varlistentry>
<varlistentry>
<term>ATMEL AT76C5XXx driver for USB and PCMCIA cards</term>
<listitem>
<para> (http://atmelwlandriver.sourceforge.net/).</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Linux ndiswrapper</term>
<listitem>
<para> (http://ndiswrapper.sourceforge.net/) with Windows
NDIS driver.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Broadcom wl.o driver</term>
<listitem>
<para> This is a generic Linux driver for Broadcom IEEE
802.11a/g cards. However, it is proprietary driver that is
not publicly available except for couple of exceptions, mainly
Broadcom-based APs/wireless routers that use Linux. The driver
binary can be downloaded, e.g., from Linksys support site
(http://www.linksys.com/support/gpl.asp) for Linksys
WRT54G. The GPL tarball includes cross-compiler and the needed
header file, wlioctl.h, for compiling wpa_supplicant. This
driver support in wpa_supplicant is expected to work also with
other devices based on Broadcom driver (assuming the driver
includes client mode support).</para>
</listitem>
</varlistentry>
<varlistentry>
<term> Intel ipw2100 driver</term>
<listitem>
<para> (http://sourceforge.net/projects/ipw2100/)</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Intel ipw2200 driver</term>
<listitem>
<para> (http://sourceforge.net/projects/ipw2200/)</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Linux wireless extensions</term>
<listitem>
<para>In theory, any driver that supports Linux wireless
extensions can be used with IEEE 802.1X (i.e., not WPA) when
using ap_scan=0 option in configuration file.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Wired Ethernet drivers</term>
<listitem>
<para>Use ap_scan=0.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>BSD net80211 layer (e.g., Atheros driver)</term>
<listitem>
<para>At the moment, this is for FreeBSD 6-CURRENT branch.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Windows NDIS</term>
<listitem>
<para>The current Windows port requires WinPcap
(http://winpcap.polito.it/). See README-Windows.txt for more
information.</para>
</listitem>
</varlistentry>
</variablelist>
<para>wpa_supplicant was designed to be portable for different
drivers and operating systems. Hopefully, support for more wlan
cards and OSes will be added in the future. See developer.txt for
more information about the design of wpa_supplicant and porting to
other drivers. One main goal is to add full WPA/WPA2 support to
Linux wireless extensions to allow new drivers to be supported
without having to implement new driver-specific interface code in
wpa_supplicant.</para>
</refsect1>
<refsect1>
<title>Architecture</title> <para>The
<command>wpa_supplicant</command> system consists of the following
components:</para>
<variablelist>
<varlistentry>
<term><filename>wpa_supplicant.conf</filename> </term>
<listitem>
<para>the configuration file describing all networks that the
user wants the computer to connect to. </para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>wpa_supplicant</command></term>
<listitem><para>the program that directly interacts with the
network interface. </para></listitem>
</varlistentry>
<varlistentry>
<term><command>wpa_cli</command></term> <listitem><para> the
client program that provides a high-level interface to the
functionality of the daemon. </para></listitem>
</varlistentry>
<varlistentry>
<term><command>wpa_passphrase</command></term>
<listitem><para>a utility needed to construct
<filename>wpa_supplicant.conf</filename> files that include
encrypted passwords.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Quick Start</title>
<para>First, make a configuration file, e.g.
<filename>/etc/wpa_supplicant.conf</filename>, that describes the networks
you are interested in. See <citerefentry>
<refentrytitle>wpa_supplicant</refentrytitle>
<manvolnum>5</manvolnum>
</citerefentry>
for details.</para>
<para>Once the configuration is ready, you can test whether the
configuration works by running <command>wpa_supplicant</command>
with following command to start it on foreground with debugging
enabled:</para>
<blockquote><programlisting>
wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -d
</programlisting></blockquote>
<para>Assuming everything goes fine, you can start using following
command to start <command>wpa_supplicant</command> on background
without debugging:</para>
<blockquote><programlisting>
wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -B
</programlisting></blockquote>
<para>Please note that if you included more than one driver
interface in the build time configuration (.config), you may need
to specify which interface to use by including -D&lt;driver
name&gt; option on the command line.</para>
<!-- XXX at this point, the page could include a little script
based on wpa_cli to wait for a connection and then run
dhclient -->
</refsect1>
<refsect1>
<title>Interface to pcmcia-cs/cardmrg</title>
<para>For example, following small changes to pcmcia-cs scripts
can be used to enable WPA support:</para>
<para>Add MODE="Managed" and WPA="y" to the network scheme in
<filename>/etc/pcmcia/wireless.opts</filename>.</para>
<para>Add the following block to the end of 'start' action handler
in <filename>/etc/pcmcia/wireless</filename>:</para>
<blockquote><programlisting>
if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then
/usr/local/bin/wpa_supplicant -Bw -c/etc/wpa_supplicant.conf -i$DEVICE
fi
</programlisting></blockquote>
<para>Add the following block to the end of 'stop' action handler
(may need to be separated from other actions) in
<filename>/etc/pcmcia/wireless</filename>:</para>
<blockquote><programlisting>
if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then
killall wpa_supplicant
fi
</programlisting></blockquote>
<para>This will make <command>cardmgr</command> start
<command>wpa_supplicant</command> when the card is plugged
in. <command>wpa_supplicant</command> will wait until the
interface is set up--either when a static IP address is configured
or when DHCP client is started--and will then negotiate keys with
the AP.</para>
</refsect1>
<refsect1>
<title>See Also</title>
<para>
<citerefentry>
<refentrytitle>wpa_background</refentrytitle>
<manvolnum>8</manvolnum>
</citerefentry>
<citerefentry>
<refentrytitle>wpa_supplicant.conf</refentrytitle>
<manvolnum>5</manvolnum>
</citerefentry>
<citerefentry>
<refentrytitle>wpa_cli</refentrytitle>
<manvolnum>8</manvolnum>
</citerefentry>
<citerefentry>
<refentrytitle>wpa_passphrase</refentrytitle>
<manvolnum>8</manvolnum>
</citerefentry>
</para>
</refsect1>
<refsect1>
<title>Legal</title>
<para>wpa_supplicant is copyright (c) 2003-2005,
Jouni Malinen <email>jkmaline@cc.hut.fi</email> and
contributors.
All Rights Reserved.</para>
<para>This program is dual-licensed under both the GPL version 2
and BSD license. Either license may be used at your option.</para>
</refsect1>
</refentry>

View file

@ -0,0 +1,243 @@
# Doxyfile 1.4.1
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
PROJECT_NAME = wpa_supplicant
PROJECT_NUMBER = 0.4.x
OUTPUT_DIRECTORY = doc
CREATE_SUBDIRS = NO
OUTPUT_LANGUAGE = English
USE_WINDOWS_ENCODING = NO
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = YES
ABBREVIATE_BRIEF = "The $name class" \
"The $name widget" \
"The $name file" \
is \
provides \
specifies \
contains \
represents \
a \
an \
the
ALWAYS_DETAILED_SEC = NO
INLINE_INHERITED_MEMB = NO
FULL_PATH_NAMES = YES
STRIP_FROM_PATH =
STRIP_FROM_INC_PATH =
SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
DETAILS_AT_TOP = NO
INHERIT_DOCS = YES
DISTRIBUTE_GROUP_DOC = NO
TAB_SIZE = 8
ALIASES =
OPTIMIZE_OUTPUT_FOR_C = YES
OPTIMIZE_OUTPUT_JAVA = NO
SUBGROUPING = YES
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
EXTRACT_ALL = NO
EXTRACT_PRIVATE = NO
EXTRACT_STATIC = NO
EXTRACT_LOCAL_CLASSES = YES
EXTRACT_LOCAL_METHODS = NO
HIDE_UNDOC_MEMBERS = NO
HIDE_UNDOC_CLASSES = NO
HIDE_FRIEND_COMPOUNDS = NO
HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO
CASE_SENSE_NAMES = YES
HIDE_SCOPE_NAMES = NO
SHOW_INCLUDE_FILES = YES
INLINE_INFO = YES
SORT_MEMBER_DOCS = YES
SORT_BRIEF_DOCS = NO
SORT_BY_SCOPE_NAME = NO
GENERATE_TODOLIST = YES
GENERATE_TESTLIST = YES
GENERATE_BUGLIST = YES
GENERATE_DEPRECATEDLIST= YES
ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30
SHOW_USED_FILES = YES
SHOW_DIRECTORIES = NO
FILE_VERSION_FILTER =
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
#---------------------------------------------------------------------------
QUIET = NO
WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES
WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = YES
WARN_FORMAT = "$file:$line: $text"
WARN_LOGFILE =
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
INPUT = . \
../hostapd/aes.c \
../hostapd/rc4.c \
../hostapd/rc4.h \
../hostapd/md5.c \
../hostapd/md5.h \
../hostapd/sha1.c \
../hostapd/sha1.h \
../hostapd/common.c \
../hostapd/common.h \
../hostapd/eloop.c \
../hostapd/eloop.h \
../hostapd/aes_wrap.c \
../hostapd/aes_wrap.h
FILE_PATTERNS = *.c *.h *.doxygen
RECURSIVE = YES
EXCLUDE =
EXCLUDE_SYMLINKS = NO
EXCLUDE_PATTERNS =
EXAMPLE_PATH =
EXAMPLE_PATTERNS = *
EXAMPLE_RECURSIVE = NO
IMAGE_PATH = doc
INPUT_FILTER = kerneldoc2doxygen.pl
FILTER_PATTERNS =
FILTER_SOURCE_FILES = YES
#---------------------------------------------------------------------------
# configuration options related to source browsing
#---------------------------------------------------------------------------
SOURCE_BROWSER = YES
INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = YES
REFERENCED_BY_RELATION = NO
REFERENCES_RELATION = NO
VERBATIM_HEADERS = NO
#---------------------------------------------------------------------------
# configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
ALPHABETICAL_INDEX = YES
COLS_IN_ALPHA_INDEX = 3
IGNORE_PREFIX =
#---------------------------------------------------------------------------
# configuration options related to the HTML output
#---------------------------------------------------------------------------
GENERATE_HTML = YES
HTML_OUTPUT = html
HTML_FILE_EXTENSION = .html
HTML_HEADER =
HTML_FOOTER =
HTML_STYLESHEET =
HTML_ALIGN_MEMBERS = YES
GENERATE_HTMLHELP = NO
CHM_FILE =
HHC_LOCATION =
GENERATE_CHI = NO
BINARY_TOC = NO
TOC_EXPAND = NO
DISABLE_INDEX = NO
ENUM_VALUES_PER_LINE = 4
GENERATE_TREEVIEW = NO
TREEVIEW_WIDTH = 250
#---------------------------------------------------------------------------
# configuration options related to the LaTeX output
#---------------------------------------------------------------------------
GENERATE_LATEX = NO
LATEX_OUTPUT = latex
LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex
COMPACT_LATEX = NO
PAPER_TYPE = a4wide
EXTRA_PACKAGES =
LATEX_HEADER =
PDF_HYPERLINKS = YES
USE_PDFLATEX = YES
LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO
#---------------------------------------------------------------------------
# configuration options related to the RTF output
#---------------------------------------------------------------------------
GENERATE_RTF = NO
RTF_OUTPUT = rtf
COMPACT_RTF = NO
RTF_HYPERLINKS = NO
RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE =
#---------------------------------------------------------------------------
# configuration options related to the man page output
#---------------------------------------------------------------------------
GENERATE_MAN = NO
MAN_OUTPUT = man
MAN_EXTENSION = .3
MAN_LINKS = NO
#---------------------------------------------------------------------------
# configuration options related to the XML output
#---------------------------------------------------------------------------
GENERATE_XML = NO
XML_OUTPUT = xml
XML_SCHEMA =
XML_DTD =
XML_PROGRAMLISTING = YES
#---------------------------------------------------------------------------
# configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
# configuration options related to the Perl module output
#---------------------------------------------------------------------------
GENERATE_PERLMOD = NO
PERLMOD_LATEX = NO
PERLMOD_PRETTY = YES
PERLMOD_MAKEVAR_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = NO
EXPAND_ONLY_PREDEF = NO
SEARCH_INCLUDES = YES
INCLUDE_PATH =
INCLUDE_FILE_PATTERNS =
PREDEFINED = IEEE8021X_EAPOL
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
# Configuration::additions related to external references
#---------------------------------------------------------------------------
TAGFILES =
GENERATE_TAGFILE =
ALLEXTERNALS = NO
EXTERNAL_GROUPS = YES
PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
CLASS_DIAGRAMS = NO
HIDE_UNDOC_RELATIONS = YES
HAVE_DOT = NO
CLASS_GRAPH = YES
COLLABORATION_GRAPH = YES
GROUP_GRAPHS = YES
UML_LOOK = NO
TEMPLATE_RELATIONS = NO
INCLUDE_GRAPH = YES
INCLUDED_BY_GRAPH = YES
CALL_GRAPH = YES
GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = NO
DOT_IMAGE_FORMAT = png
DOT_PATH =
DOTFILE_DIRS =
MAX_DOT_GRAPH_WIDTH = 1024
MAX_DOT_GRAPH_HEIGHT = 1024
MAX_DOT_GRAPH_DEPTH = 1000
DOT_TRANSPARENT = NO
DOT_MULTI_TARGETS = NO
GENERATE_LEGEND = YES
DOT_CLEANUP = YES
#---------------------------------------------------------------------------
# Configuration::additions related to the search engine
#---------------------------------------------------------------------------
SEARCHENGINE = NO

View file

@ -0,0 +1,230 @@
# Doxyfile 1.4.1
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
PROJECT_NAME = wpa_supplicant
PROJECT_NUMBER = 0.4.x
OUTPUT_DIRECTORY = doc
CREATE_SUBDIRS = NO
OUTPUT_LANGUAGE = English
USE_WINDOWS_ENCODING = NO
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = YES
ABBREVIATE_BRIEF = "The $name class" \
"The $name widget" \
"The $name file" \
is \
provides \
specifies \
contains \
represents \
a \
an \
the
ALWAYS_DETAILED_SEC = NO
INLINE_INHERITED_MEMB = NO
FULL_PATH_NAMES = YES
STRIP_FROM_PATH =
STRIP_FROM_INC_PATH =
SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
DETAILS_AT_TOP = NO
INHERIT_DOCS = YES
DISTRIBUTE_GROUP_DOC = NO
TAB_SIZE = 8
ALIASES =
OPTIMIZE_OUTPUT_FOR_C = YES
OPTIMIZE_OUTPUT_JAVA = NO
SUBGROUPING = YES
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
EXTRACT_ALL = NO
EXTRACT_PRIVATE = NO
EXTRACT_STATIC = NO
EXTRACT_LOCAL_CLASSES = YES
EXTRACT_LOCAL_METHODS = NO
HIDE_UNDOC_MEMBERS = NO
HIDE_UNDOC_CLASSES = NO
HIDE_FRIEND_COMPOUNDS = NO
HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO
CASE_SENSE_NAMES = YES
HIDE_SCOPE_NAMES = NO
SHOW_INCLUDE_FILES = YES
INLINE_INFO = YES
SORT_MEMBER_DOCS = YES
SORT_BRIEF_DOCS = NO
SORT_BY_SCOPE_NAME = NO
GENERATE_TODOLIST = YES
GENERATE_TESTLIST = YES
GENERATE_BUGLIST = YES
GENERATE_DEPRECATEDLIST= YES
ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30
SHOW_USED_FILES = YES
SHOW_DIRECTORIES = NO
FILE_VERSION_FILTER =
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
#---------------------------------------------------------------------------
QUIET = NO
WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES
WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = YES
WARN_FORMAT = "$file:$line: $text"
WARN_LOGFILE =
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
INPUT = .
FILE_PATTERNS = *.c *.h *.doxygen
RECURSIVE = YES
EXCLUDE =
EXCLUDE_SYMLINKS = NO
EXCLUDE_PATTERNS =
EXAMPLE_PATH =
EXAMPLE_PATTERNS = *
EXAMPLE_RECURSIVE = NO
IMAGE_PATH = doc
INPUT_FILTER = kerneldoc2doxygen.pl
FILTER_PATTERNS =
FILTER_SOURCE_FILES = YES
#---------------------------------------------------------------------------
# configuration options related to source browsing
#---------------------------------------------------------------------------
SOURCE_BROWSER = YES
INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = YES
REFERENCED_BY_RELATION = NO
REFERENCES_RELATION = NO
VERBATIM_HEADERS = NO
#---------------------------------------------------------------------------
# configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
ALPHABETICAL_INDEX = YES
COLS_IN_ALPHA_INDEX = 3
IGNORE_PREFIX =
#---------------------------------------------------------------------------
# configuration options related to the HTML output
#---------------------------------------------------------------------------
GENERATE_HTML = YES
HTML_OUTPUT = html
HTML_FILE_EXTENSION = .html
HTML_HEADER =
HTML_FOOTER =
HTML_STYLESHEET =
HTML_ALIGN_MEMBERS = YES
GENERATE_HTMLHELP = NO
CHM_FILE =
HHC_LOCATION =
GENERATE_CHI = NO
BINARY_TOC = NO
TOC_EXPAND = NO
DISABLE_INDEX = NO
ENUM_VALUES_PER_LINE = 4
GENERATE_TREEVIEW = NO
TREEVIEW_WIDTH = 250
#---------------------------------------------------------------------------
# configuration options related to the LaTeX output
#---------------------------------------------------------------------------
GENERATE_LATEX = YES
LATEX_OUTPUT = latex
LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex
COMPACT_LATEX = NO
PAPER_TYPE = a4wide
EXTRA_PACKAGES =
LATEX_HEADER =
PDF_HYPERLINKS = YES
USE_PDFLATEX = YES
LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO
#---------------------------------------------------------------------------
# configuration options related to the RTF output
#---------------------------------------------------------------------------
GENERATE_RTF = NO
RTF_OUTPUT = rtf
COMPACT_RTF = NO
RTF_HYPERLINKS = NO
RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE =
#---------------------------------------------------------------------------
# configuration options related to the man page output
#---------------------------------------------------------------------------
GENERATE_MAN = NO
MAN_OUTPUT = man
MAN_EXTENSION = .3
MAN_LINKS = NO
#---------------------------------------------------------------------------
# configuration options related to the XML output
#---------------------------------------------------------------------------
GENERATE_XML = NO
XML_OUTPUT = xml
XML_SCHEMA =
XML_DTD =
XML_PROGRAMLISTING = YES
#---------------------------------------------------------------------------
# configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
# configuration options related to the Perl module output
#---------------------------------------------------------------------------
GENERATE_PERLMOD = NO
PERLMOD_LATEX = NO
PERLMOD_PRETTY = YES
PERLMOD_MAKEVAR_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = NO
EXPAND_ONLY_PREDEF = NO
SEARCH_INCLUDES = YES
INCLUDE_PATH =
INCLUDE_FILE_PATTERNS =
PREDEFINED = IEEE8021X_EAPOL
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
# Configuration::additions related to external references
#---------------------------------------------------------------------------
TAGFILES =
GENERATE_TAGFILE =
ALLEXTERNALS = NO
EXTERNAL_GROUPS = YES
PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
CLASS_DIAGRAMS = NO
HIDE_UNDOC_RELATIONS = YES
HAVE_DOT = YES
CLASS_GRAPH = YES
COLLABORATION_GRAPH = YES
GROUP_GRAPHS = YES
UML_LOOK = NO
TEMPLATE_RELATIONS = NO
INCLUDE_GRAPH = YES
INCLUDED_BY_GRAPH = YES
CALL_GRAPH = YES
GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = NO
DOT_IMAGE_FORMAT = png
DOT_PATH =
DOTFILE_DIRS =
MAX_DOT_GRAPH_WIDTH = 1024
MAX_DOT_GRAPH_HEIGHT = 1024
MAX_DOT_GRAPH_DEPTH = 1000
DOT_TRANSPARENT = NO
DOT_MULTI_TARGETS = NO
GENERATE_LEGEND = YES
DOT_CLEANUP = YES
#---------------------------------------------------------------------------
# Configuration::additions related to the search engine
#---------------------------------------------------------------------------
SEARCHENGINE = YES

View file

@ -0,0 +1,180 @@
/**
\page driver_wrapper Driver wrapper implementation (driver.h, drivers.c)
All hardware and driver dependent functionality is in separate C files
that implement defined wrapper functions. Other parts
of the %wpa_supplicant are designed to be hardware, driver, and operating
system independent.
Driver wrappers need to implement whatever calls are used in the
target operating system/driver for controlling wireless LAN
devices. As an example, in case of Linux, these are mostly some glue
code and ioctl() calls and netlink message parsing for Linux Wireless
Extensions (WE). Since features required for WPA were added only recently to
Linux Wireless Extensions (in version 18), some driver specific code is used
in number of driver interface implementations. These driver dependent parts
can be replaced with generic code in driver_wext.c once the target driver
includes full support for WE-18. After that, all Linux drivers, at
least in theory, could use the same driver wrapper code.
A driver wrapper needs to implement some or all of the functions
defined in driver.h. These functions are registered by filling struct
wpa_driver_ops with function pointers. Hardware independent parts of
%wpa_supplicant will call these functions to control the driver/wlan
card. In addition, support for driver events is required. The event
callback function, wpa_supplicant_event(), and its parameters are
documented in wpa_supplicant.h. In addition, a pointer to the 'struct
wpa_driver_ops' needs to be registered in drivers.c file.
When porting to other operating systems, the driver wrapper should be
modified to use the native interface of the target OS. It is possible
that some extra requirements for the interface between the driver
wrapper and generic %wpa_supplicant code are discovered during porting
to a new operating system. These will be addressed on case by case
basis by modifying the interface and updating the other driver
wrappers for this. The goal is to avoid changing this interface
without very good reasons in order to limit the number of changes
needed to other wrappers and hardware independent parts of
%wpa_supplicant. When changes are required, recommended way is to
make them in backwards compatible way that allows existing driver
interface implementations to be compiled without any modification.
Generic Linux Wireless Extensions functions are implemented in
driver_wext.c. All Linux driver wrappers can use these when the kernel
driver supports the generic ioctl()s and wireless events. Driver
specific functions are implemented in separate C files, e.g.,
driver_hostap.c. These files need to define struct wpa_driver_ops
entry that will be used in wpa_supplicant.c when calling driver
functions. struct wpa_driver_ops entries are registered in drivers.c.
In general, it is likely to be useful to first take a look at couple
of driver interface examples before starting on implementing a new
one. driver_hostap.c and driver_wext.c include a complete
implementation for Linux drivers that use %wpa_supplicant-based control
of WPA IE and roaming. driver_ndis.c (with help from driver_ndis_.c)
is an example of a complete interface for Windows NDIS interface for
drivers that generate WPA IE themselves and decide when to roam. These
example implementations include full support for all security modes.
\section driver_req Driver requirements for WPA
WPA introduces new requirements for the device driver. At least some
of these need to be implemented in order to provide enough support for
%wpa_supplicant.
\subsection driver_tkip_ccmp TKIP/CCMP
WPA requires that the pairwise cipher suite (encryption algorithm for
unicast data packets) is TKIP or CCMP. These are new encryption
protocols and thus, the driver will need to be modified to support
them. Depending on the used wlan hardware, some parts of these may be
implemented by the hardware/firmware.
Specification for both TKIP and CCMP is available from IEEE (IEEE
802.11i amendment). Fully functional, hardware independent
implementation of both encryption protocols is also available in Host
AP driver (driver/modules/hostap_{tkip,ccmp}.c). In addition, Linux 2.6
kernel tree has generic implementations for WEP, TKIP, and CCMP that can
be used in Linux drivers.
The driver will also need to provide configuration mechanism to allow
user space programs to configure TKIP and CCMP. Linux Wireless Extensions
v18 added support for configuring these algorithms and
individual/non-default keys. If the target kernel does not include WE-18,
private ioctls can be used to provide similar functionality.
\subsection driver_roaming Roaming control and scanning support
%wpa_supplicant can optionally control AP selection based on the
information received from Beacon and/or Probe Response frames
(ap_scan=1 mode in configuration). This means that the driver should
support external control for scan process. In case of Linux, use of
new Wireless Extensions scan support (i.e., 'iwlist wlan0 scan') is
recommended. The current driver wrapper (driver_wext.c) uses this for
scan results.
Scan results must also include the WPA information element. Support for
this was added in WE-18. With older versions, a custom event can be used
to provide the full WPA IE (including element id and length) as a hex
string that is included in the scan results.
%wpa_supplicant needs to also be able to request the driver to
associate with a specific BSS. Current Host AP driver and matching
driver_hostap.c wrapper uses following sequence for this
request. Similar/identical mechanism should be usable also with other
drivers.
- set WPA IE for AssocReq with private ioctl
- set SSID with SIOCSIWESSID
- set channel/frequency with SIOCSIWFREQ
- set BSSID with SIOCSIWAP
(this last ioctl will trigger the driver to request association)
\subsection driver_wpa_ie WPA IE generation
%wpa_supplicant selects which cipher suites and key management suites
are used. Based on this information, it generates a WPA IE. This is
provided to the driver interface in the associate call. This does not
match with Windows NDIS drivers which generate the WPA IE
themselves.
%wpa_supplicant allows Windows NDIS-like behavior by providing the
selected cipher and key management suites in the associate call. If
the driver generates its own WPA IE and that differs from the one
generated by %wpa_supplicant, the driver has to inform %wpa_supplicant
about the used WPA IE (i.e., the one it used in (Re)Associate
Request). This notification is done using EVENT_ASSOCINFO event (see
wpa_supplicant.h). %wpa_supplicant is normally configured to use
ap_scan=2 mode with drivers that control WPA IE generation and roaming.
\subsection driver_events Driver events
%wpa_supplicant needs to receive event callbacks when certain events
occur (association, disassociation, Michael MIC failure, scan results
available, PMKSA caching candidate). These events and the callback
details are defined in wpa_supplicant.h (wpa_supplicant_event() function
and enum wpa_event_type).
On Linux, association and disassociation can use existing Wireless
Extensions event that is reporting new AP with SIOCGIWAP
event. Similarly, completion of a scan can be reported with SIOCGIWSCAN
event.
Michael MIC failure event was added in WE-18. Older versions of Wireless
Extensions will need to use a custom event. Host AP driver used a custom
event with following contents: MLME-MICHAELMICFAILURE.indication(keyid=#
broadcast/unicast addr=addr2). This is the recommended format until
the driver can be moved to use WE-18 mechanism.
\subsection driver_wext_summary Summary of Linux Wireless Extensions use
AP selection depends on ap_scan configuration:
ap_scan=1:
- %wpa_supplicant requests scan with SIOCSIWSCAN
- driver reports scan complete with wireless event SIOCGIWSCAN
- %wpa_supplicant reads scan results with SIOCGIWSCAN (multiple call if
a larget buffer is needed)
- %wpa_supplicant decides which AP to use based on scan results
- %wpa_supplicant configures driver to associate with the selected BSS
(SIOCSIWMODE, SIOCSIWGENIE, SIOCSIWAUTH, SIOCSIWFREQ,
SIOCSIWESSID, SIOCSIWAP)
ap_scan=2:
- %wpa_supplicant configures driver to associate with an SSID
(SIOCSIWMODE, SIOCSIWGENIE, SIOCSIWAUTH, SIOCSIWESSID)
After this, both modes use similar steps:
- optionally (or required for drivers that generate WPA/RSN IE for
(Re)AssocReq), driver reports association parameters (AssocReq IEs)
with wireless event IWEVASSOCREQIE (and optionally IWEVASSOCRESPIE)
- driver reports association with wireless event SIOCGIWAP
- %wpa_supplicant takes care of EAPOL frame handling (validating
information from associnfo and if needed, from scan results if WPA/RSN
IE from the Beacon frame is not reported through associnfo)
*/

View file

@ -0,0 +1,38 @@
/**
\page eap_module EAP peer implementation
%wpa_supplicant uses a separate code module for EAP peer
implementation. This module was designed to use only a minimal set of
direct function calls (mainly, to debug/event functions) in order for
it to be usable in other programs. The design of the EAP
implementation is based loosely on RFC 4137. The state machine is
defined in this RFC and so is the interface between the peer state
machine and methods. As such, this RFC provides useful information for
understanding the EAP peer implementation in %wpa_supplicant.
Some of the terminology used in EAP state machine is referring to
EAPOL (IEEE 802.1X), but there is no strict requirement on the lower
layer being IEEE 802.1X if EAP module is built for other programs than
%wpa_supplicant. These terms should be understood to refer to the
lower layer as defined in RFC 4137.
\section adding_eap_methods Adding EAP methods
Each EAP method is implemented as a separate module, usually as one C
file named eap_<name of the method>.c, e.g., eap_md5.c. All EAP
methods use the same interface between the peer state machine and
method specific functions. This allows new EAP methods to be added
without modifying the core EAP state machine implementation.
New EAP methods need to be registered by adding them into build
(Makefile) and EAP method table in the beginning of eap.c. Each EAP
method should use a build-time configuration option, e.g., EAP_TLS, in
order to make it possible to select which of the methods are included
in the build.
EAP methods must implement the interface defined in eap_i.h. struct
eap_method defines the needed function pointers that each EAP method
must provide. In addition, the EAP type and name are registered using
this structure. This interface is based on section 4.4 of RFC 4137.
*/

View file

@ -0,0 +1,129 @@
#!/usr/bin/perl -w
#
##########################################################################
# Convert kernel-doc style comments to Doxygen comments.
##########################################################################
#
# This script reads a C source file from stdin, and writes
# to stdout. Normal usage:
#
# $ mv file.c file.c.gtkdoc
# $ kerneldoc2doxygen.pl <file.c.gtkdoc >file.c
#
# Or to do the same thing with multiple files:
# $ perl -i.gtkdoc kerneldoc2doxygen.pl *.c *.h
#
# This script may also be suitable for use as a Doxygen input filter,
# but that has not been tested.
#
# Back up your source files before using this script!!
#
##########################################################################
# Copyright (C) 2003 Jonathan Foster <jon@jon-foster.co.uk>
# Copyright (C) 2005 Jouni Malinen <jkmaline@cc.hut.fi>
# (modified for kerneldoc format used in wpa_supplicant)
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# or look at http://www.gnu.org/licenses/gpl.html
##########################################################################
##########################################################################
#
# This function converts a single comment from gtk-doc to Doxygen format.
# The parameter does not include the opening or closing lines
# (i.e. given a comment like this:
# "/**\n"
# " * FunctionName:\n"
# " * @foo: This describes the foo parameter\n"
# " * @bar: This describes the bar parameter\n"
# " * @Returns: This describes the return value\n"
# " *\n"
# " * This describes the function.\n"
# " */\n"
# This function gets:
# " * FunctionName:\n"
# " * @foo: This describes the foo parameter\n"
# " * @bar: This describes the bar parameter\n"
# " * @Returns: This describes the return value\n"
# " *\n"
# " * This describes the function.\n"
# And it returns:
# " * This describes the function.\n"
# " *\n"
# " * @param foo This describes the foo parameter\n"
# " * @param bar This describes the bar parameter\n"
# " * @return This describes the return value\n"
# )
#
sub fixcomment {
$t = $_[0];
# " * func: foo" --> "\brief foo\n"
# " * struct bar: foo" --> "\brief foo\n"
# If this fails, not a kernel-doc comment ==> return unmodified.
($t =~ s/^[\t ]*\*[\t ]*(struct )?([^ \t\n]*) - ([^\n]*)/\\brief $3\n/s)
or return $t;
# " * Returns: foo" --> "\return foo"
$t =~ s/\n[\t ]*\*[\t ]*Returns:/\n\\return/sig;
# " * @foo: bar" --> "\param foo bar"
# Handle two common typos: No ":", or "," instead of ":".
$t =~ s/\n[\t ]*\*[\t ]*\@([^ :,]*)[:,]?[\t ]*/\n\\param $1 /sg;
return $t;
}
##########################################################################
# Start of main code
# Read entire stdin into memory - one multi-line string.
$_ = do { local $/; <> };
s{^/\*\n \*}{/\*\* \\file\n\\brief};
s{ \* Copyright}{\\par Copyright\nCopyright};
# Fix any comments like "/*************" so they don't match.
# "/***" ===> "/* *"
s{/\*\*\*}{/\* \*}gs;
# The main comment-detection code.
s{
( # $1 = Open comment
/\*\* # Open comment
(?!\*) # Do not match /*** (redundant due to fixup above).
[\t ]*\n? # If 1st line is whitespace, match the lot (including the newline).
)
(.*?) # $2 = Body of comment (multi-line)
( # $3 = Close comment
( # If possible, match the whitespace before the close-comment
(?<=\n) # This part only matches after a newline
[\t ]* # Eat whitespace
)?
\*/ # Close comment
)
}
{
$1 . fixcomment($2) . $3
}gesx;
# ^^^^ Modes: g - Global, match all occurances.
# e - Evaluate the replacement as an expression.
# s - Single-line - allows the pattern to match across newlines.
# x - eXtended pattern, ignore embedded whitespace
# and allow comments.
# Write results to stdout
print $_;

View file

@ -0,0 +1,56 @@
/**
\mainpage Developers' documentation for %wpa_supplicant
%wpa_supplicant is a WPA Supplicant for Linux, BSD and Windows with
support for WPA and WPA2 (IEEE 802.11i / RSN). Supplicant is the IEEE
802.1X/WPA component that is used in the client stations. It
implements key negotiation with a WPA Authenticator and it can optionally
control roaming and IEEE 802.11 authentication/association of the wlan
driver.
The goal of this documentation and comments in the source code is to
give enough information for other developers to understand how
%wpa_supplicant has been implemented, how it can be modified, how new
drivers can be supported, and how %wpa_supplicant can be ported to
other operating systems. If any information is missing, feel free to
contact Jouni Malinen <jkmaline@cc.hut.fi> for more
information. Contributions as patch files are also very welcome at the
same address. Please note that %wpa_supplicant is licensed under dual
license, GPLv2 or BSD at user's choice. All contributions to
%wpa_supplicant are expected to use compatible licensing terms.
The source code and read-only access to %wpa_supplicant CVS repository
is available from the project home page at
http://hostap.epitest.fi/wpa_supplicant/. This developers' documentation
is also available as a PDF file from
http://hostap.epitest.fi/wpa_supplicant/wpa_supplicant-devel.pdf .
The design goal for %wpa_supplicant was to use hardware, driver, and
OS independent, portable C code for all WPA functionality. The source
code is divided into separate C files as shown on the \ref
code_structure "code structure page". All hardware/driver specific
functionality is in separate files that implement a \ref
driver_wrapper "well-defined driver API". Information about porting
to different target boards and operating systems is available on
the \ref porting "porting page".
EAPOL (IEEE 802.1X) state machines are implemented as a separate
module that interacts with \ref eap_module "EAP peer implementation".
In addition to programs aimed at normal production use,
%wpa_supplicant source tree includes number of \ref testing_tools
"testing and development tools" that make it easier to test the
programs without having to setup a full test setup with wireless
cards. These tools can also be used to implement automatic test
suites.
%wpa_supplicant implements a
\ref ctrl_iface_page "control interface" that can be used by
external programs to control the operations of the %wpa_supplicant
daemon and to get status information and event notifications. There is
a small C library that provides helper functions to facilitate the use of the
control interface. This library can also be used with C++.
\image html wpa_supplicant.png "wpa_supplicant modules"
\image latex wpa_supplicant.eps "wpa_supplicant modules" width=15cm
*/

View file

@ -0,0 +1,121 @@
/**
\page porting Porting to different target boards and operating systems
%wpa_supplicant was designed to be easily portable to different
hardware (board, CPU) and software (OS, drivers) targets. It is
already used with number of operating systems and numerous wireless
card models and drivers. The main %wpa_supplicant repository includes
support for Linux, FreeBSD, and Windows. In addition, at least VxWorks
and PalmOS are supported in separate repositories. On the hardware
side, %wpa_supplicant is used on various systems: desktops, laptops,
PDAs, and embedded devices with CPUs including x86, PowerPC,
arm/xscale, and MIPS. Both big and little endian configurations are
supported.
\section driver_iface_porting Driver interface
Unless the target OS and driver is already supported, most porting
projects have to implement a driver wrapper. This may be done by
adding a new driver interface module or modifying an existing module
(driver_*.c) if the new target is similar to one of them. \ref
driver_wrapper "Driver wrapper implementation" describes the details
of the driver interface and discusses the tasks involved in porting
this part of %wpa_supplicant.
\section l2_packet_porting l2_packet (link layer access)
%wpa_supplicant needs to have access to sending and receiving layer 2
(link layer) packets with two Ethertypes: EAP-over-LAN (EAPOL) 0x888e
and RSN pre-authentication 0x88c7. l2_packet.h defines the interfaces
used for this in the core %wpa_supplicant implementation.
If the target operating system supports a generic mechanism for link
layer access, that is likely the best mechanism for providing the
needed functionality for %wpa_supplicant. Linux packet socket is an
example of such a generic mechanism. If this is not available, a
separate interface may need to be implemented to the network stack or
driver. This is usually an intermediate or protocol driver that is
operating between the device driver and the OS network stack. If such
a mechanism is not feasible, the interface can also be implemented
directly in the device driver.
The main %wpa_supplicant repository includes l2_packet implementations
for Linux using packet sockets (l2_packet_linux.c), more portable
version using libpcap/libdnet libraries (l2_packet_pcap.c; this
supports WinPcap, too), and FreeBSD specific version of libpcap
interface (l2_packet_freebsd.c).
If the target operating system is supported by libpcap (receiving) and
libdnet (sending), l2_packet_pcap.c can likely be used with minimal or
no changes. If this is not a case or a proprietary interface for link
layer is required, a new l2_packet module may need to be
added. Alternatively, struct wpa_driver_ops::send_eapol() handler can
be used to override the l2_packet library if the link layer access is
integrated with the driver interface implementation.
\section eloop_porting Event loop
%wpa_supplicant uses a single process/thread model and an event loop
to provide callbacks on events (registered timeout, received packet,
signal). eloop.h defines the event loop interface. eloop.c is an
implementation of such an event loop using select() and sockets. This
is suitable for most UNIX/POSIX systems. When porting to other
operating systems, it may be necessary to replace that implementation
with OS specific mechanisms that provide similar functionality.
\section ctrl_iface_porting Control interface
%wpa_supplicant uses a \ref ctrl_iface_page "control interface"
to allow external processed
to get status information and to control the operations. Currently,
this is implemented with socket based communication; both UNIX domain
sockets and UDP sockets are supported. If the target OS does not
support sockets, this interface will likely need to be modified to use
another mechanism like message queues. The control interface is
optional component, so it is also possible to run %wpa_supplicant
without porting this part.
The %wpa_supplicant side of the control interface is implemented in
ctrl_iface.c. Matching client side is implemented as a control
interface library in wpa_ctrl.c.
\section entry_point Program entry point
%wpa_supplicant defines a set of functions that can be used to
initialize main supplicant processing. Each operating system has a
mechanism for starting new processing or threads. This is usually a
function with a specific set of arguments and calling convention. This
function is responsible on initializing %wpa_supplicant.
main.c includes an entry point for UNIX-like operating system, i.e.,
main() function that uses command line arguments for setting
parameters for %wpa_supplicant. When porting to other operating
systems, similar OS-specific entry point implementation is needed. It
can be implemented in a new file that is then linked with
%wpa_supplicant instead of main.o. main.c is also a good example on
how the initialization process should be done.
The supplicant initialization functions are defined in
wpa_supplicant_i.h. In most cases, the entry point function should
start by fetching configuration parameters. After this, a global
%wpa_supplicant context is initialized with a call to
wpa_supplicant_init(). After this, existing network interfaces can be
added with wpa_supplicant_add_iface(). wpa_supplicant_run() is then
used to start the main event loop. Once this returns at program
termination time, wpa_supplicant_deinit() is used to release global
context data.
wpa_supplicant_add_iface() and wpa_supplicant_remove_iface() can be
used dynamically to add and remove interfaces based on when
%wpa_supplicant processing is needed for them. This can be done, e.g.,
when hotplug network adapters are being inserted and ejected. It is
also possible to do this when a network interface is being
enabled/disabled if it is desirable that %wpa_supplicant processing
for the interface is fully enabled/disabled at the same time.
*/

View file

@ -0,0 +1,288 @@
/**
\page testing_tools Testing and development tools
[ \ref eapol_test "eapol_test" |
\ref preauth_test "preauth_test" |
\ref driver_test "driver_test" |
\ref unit_tests "Unit tests" ]
%wpa_supplicant source tree includes number of testing and development
tools that make it easier to test the programs without having to setup
a full test setup with wireless cards. In addition, these tools can be
used to implement automatic tests suites.
\section eapol_test eapol_test - EAP peer and RADIUS client testing
eapol_test is a program that links together the same EAP peer
implementation that %wpa_supplicant is using and the RADIUS
authentication client code from hostapd. In addition, it has minimal
glue code to combine these two components in similar ways to IEEE
802.1X/EAPOL Authenticator state machines. In other words, it
integrates IEEE 802.1X Authenticator (normally, an access point) and
IEEE 802.1X Supplicant (normally, a wireless client) together to
generate a single program that can be used to test EAP methods without
having to setup an access point and a wireless client.
The main uses for eapol_test are in interoperability testing of EAP
methods against RADIUS servers and in development testing for new EAP
methods. It can be easily used to automate EAP testing for
interoperability and regression since the program can be run from
shell scripts without require additional test components apart from a
RADIUS server. For example, the automated EAP tests described in
eap_testing.txt are implemented with eapol_test. Similarly, eapol_test
could be used to implement an automated regression test suite for a
RADIUS authentication server.
eapol_test uses the same build time configuration file, .config, as
%wpa_supplicant. This file is used to select which EAP methods are
included in eapol_test. This program is not built with the default
Makefile target, so a separate make command needs to be used to
compile the tool:
\verbatim
make eapol_test
\endverbatim
The resulting eapol_test binary has following command like options:
\verbatim
usage:
eapol_test [-nW] -c<conf> [-a<AS IP>] [-p<AS port>] [-s<AS secret>] [-r<count>]
eapol_test scard
eapol_test sim <PIN> <num triplets> [debug]
options:
-c<conf> = configuration file
-a<AS IP> = IP address of the authentication server, default 127.0.0.1
-p<AS port> = UDP port of the authentication server, default 1812
-s<AS secret> = shared secret with the authentication server, default 'radius'
-r<count> = number of re-authentications
-W = wait for a control interface monitor before starting
-n = no MPPE keys expected
\endverbatim
As an example,
\verbatim
eapol_test -ctest.conf -a127.0.0.1 -p1812 -ssecret -r1
\endverbatim
tries to complete EAP authentication based on the network
configuration from test.conf against the RADIUS server running on the
local host. A re-authentication is triggered to test fast
re-authentication. The configuration file uses the same format for
network blocks as %wpa_supplicant.
\section preauth_test preauth_test - WPA2 pre-authentication and EAP peer testing
preauth_test is similar to eapol_test in the sense that in combines
EAP peer implementation with something else, in this case, with WPA2
pre-authentication. This tool can be used to test pre-authentication
based on the code that %wpa_supplicant is using. As such, it tests
both the %wpa_supplicant implementation and the functionality of an
access point.
preauth_test is built with:
\verbatim
make preauth_test
\endverbatim
and it uses following command line arguments:
\verbatim
usage: preauth_test <conf> <target MAC address> <ifname>
\endverbatim
For example,
\verbatim
preauth_test test.conf 02:11:22:33:44:55 eth0
\endverbatim
would use network configuration from test.conf to try to complete
pre-authentication with AP using BSSID 02:11:22:33:44:55. The
pre-authentication packets would be sent using the eth0 interface.
\section driver_test driver_test - driver interface for testing wpa_supplicant
%wpa_supplicant was designed to support number of different ways to
communicate with a network device driver. This design uses \ref
driver_wrapper "driver interface API" and number of driver interface
implementations. One of these is driver_test.c, i.e., a test driver
interface that is actually not using any drivers. Instead, it provides
a mechanism for running %wpa_supplicant without having to have a
device driver or wireless LAN hardware for that matter.
driver_test can be used to talk directly with hostapd's driver_test
component to create a test setup where one or more clients and access
points can be tested within one test host and without having to have
multiple wireless cards. This makes it easier to test the core code in
%wpa_supplicant, and hostapd for that matter. Since driver_test uses
the same driver API than any other driver interface implementation,
the core code of %wpa_supplicant and hostapd can be tested with the
same coverage as one would get when using real wireless cards. The
only area that is not tested is the driver interface implementation
(driver_*.c).
Having the possibility to use simulated network components makes it
much easier to do development testing while adding new features and to
reproduce reported bugs. As such, it is often easiest to just do most
of the development and bug fixing without using real hardware. Once
the driver_test setup has been used to implement a new feature or fix
a bug, the end result can be verified with wireless LAN cards. In many
cases, this may even be unnecessary, depending on what area the
feature/bug is relating to. Of course, changes to driver interfaces
will still require use of real hardware.
Since multiple components can be run within a single host, testing of
complex network configuration, e.g., large number of clients
association with an access point, becomes quite easy. All the tests
can also be automated without having to resort to complex test setup
using remote access to multiple computers.
driver_test can be included in the %wpa_supplicant build in the same
way as any other driver interface, i.e., by adding the following line
into .config:
\verbatim
CONFIG_DRIVER_TEST=y
\endverbatim
When running %wpa_supplicant, the test interface is selected by using
\a -Dtest command line argument. The interface name (\a -i argument)
can be selected arbitrarily, i.e., it does not need to match with any
existing network interface. The interface name is used to generate a
MAC address, so when using multiple clients, each should use a
different interface, e.g., \a sta1, \a sta2, and so on.
%wpa_supplicant and hostapd are configured in the same way as they
would be for normal use. Following example shows a simple test setup
for WPA-PSK.
hostapd is configured with following psk-test.conf configuration file:
\verbatim
driver=test
interface=ap1
logger_stdout=-1
logger_stdout_level=0
debug=2
dump_file=/tmp/hostapd.dump
test_socket=/tmp/Test/ap1
ssid=jkm-test-psk
wpa=1
wpa_key_mgmt=WPA-PSK
wpa_pairwise=TKIP
wpa_passphrase=12345678
\endverbatim
and started with following command:
\verbatim
hostapd psk-test.conf
\endverbatim
%wpa_supplicant uses following configuration file:
\verbatim
driver_param=test_socket=/tmp/Test/ap1
network={
ssid="jkm-test-psk"
key_mgmt=WPA-PSK
psk="12345678"
}
\endverbatim
%wpa_supplicant can then be started with following command:
\verbatim
wpa_supplicant -Dtest -cpsk-test.conf -ista1 -ddK
\endverbatim
If run without debug information, i.e., with
\verbatim
wpa_supplicant -Dtest -cpsk-test.conf -ista1
\endverbatim
%wpa_supplicant completes authentication and prints following events:
\verbatim
Trying to associate with 02:b8:a6:62:08:5a (SSID='jkm-test-psk' freq=0 MHz)
Associated with 02:b8:a6:62:08:5a
WPA: Key negotiation completed with 02:b8:a6:62:08:5a [PTK=TKIP GTK=TKIP]
CTRL-EVENT-CONNECTED - Connection to 02:b8:a6:62:08:5a completed (auth)
\endverbatim
If test setup is using multiple clients, it is possible to run
multiple %wpa_supplicant processes. Alternatively, the support for
multiple interfaces can be used with just one process to save some
resources on single-CPU systems. For example, following command runs
two clients:
\verbatim
./wpa_supplicant -Dtest -cpsk-test.conf -ista1 \
-N -Dtest -cpsk-test.conf -ista2
\endverbatim
This shows following event log:
\verbatim
Trying to associate with 02:b8:a6:62:08:5a (SSID='jkm-test-psk' freq=0 MHz)
Associated with 02:b8:a6:62:08:5a
WPA: Key negotiation completed with 02:b8:a6:62:08:5a [PTK=TKIP GTK=TKIP]
CTRL-EVENT-CONNECTED - Connection to 02:b8:a6:62:08:5a completed (auth)
Trying to associate with 02:b8:a6:62:08:5a (SSID='jkm-test-psk' freq=0 MHz)
Associated with 02:b8:a6:62:08:5a
WPA: Key negotiation completed with 02:b8:a6:62:08:5a [PTK=TKIP GTK=TKIP]
CTRL-EVENT-CONNECTED - Connection to 02:b8:a6:62:08:5a completed (auth)
\endverbatim
hostapd shows this with following events:
\verbatim
ap1: STA 02:b5:64:63:30:63 IEEE 802.11: associated
ap1: STA 02:b5:64:63:30:63 WPA: pairwise key handshake completed (WPA)
ap1: STA 02:b5:64:63:30:63 WPA: group key handshake completed (WPA)
ap1: STA 02:2a:c4:18:5b:f3 IEEE 802.11: associated
ap1: STA 02:2a:c4:18:5b:f3 WPA: pairwise key handshake completed (WPA)
ap1: STA 02:2a:c4:18:5b:f3 WPA: group key handshake completed (WPA)
\endverbatim
By default, driver_param is simulating a driver that uses the WPA/RSN
IE generated by %wpa_supplicant. Driver-generated IE and AssocInfo
events can be tested by adding \a use_associnfo=1 to the \a driver_param
line in the configuration file. For example:
\verbatim
driver_param=test_socket=/tmp/Test/ap1 use_associnfo=1
\endverbatim
\section unit_tests Unit tests
Number of the components (.c files) used in %wpa_supplicant define
their own unit tests for automated validation of the basic
functionality. Most of the tests for cryptographic algorithms are
using standard test vectors to validate functionality. These tests can
be useful especially when verifying port to a new CPU target.
In most cases, these tests are implemented in the end of the same file
with functions that are normally commented out, but ca be included by
defining a pre-processor variable when building the file separately.
The details of the needed build options are included in the Makefile
(test-* targets). All automated unit tests can be run with
\verbatim
make tests
\endverbatim
This make target builds and runs each test and terminates with zero
exit code if all tests were completed successfully.
*/

View file

@ -117,7 +117,7 @@ Single
9600 3000 10275 3000 10275 3300 9600 3300 9600 3000
4 0 0 50 -1 0 12 0.0000 4 135 315 9750 3225 TLS\001
-6
6 8100 4425 10425 6975
6 8100 4425 10425 7350
6 8175 4725 9225 5025
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
8175 4725 9225 4725 9225 5025 8175 5025 8175 4725
@ -153,11 +153,6 @@ Single
8175 5850 9225 5850 9225 6150 8175 6150 8175 5850
4 0 0 50 -1 0 12 0.0000 4 135 750 8250 6075 EAP-SIM\001
-6
6 8175 6600 9675 6900
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
8175 6600 9675 6600 9675 6900 8175 6900 8175 6600
4 0 0 50 -1 0 12 0.0000 4 135 1365 8250 6825 EAP-MSCHAPv2\001
-6
6 9300 6225 10350 6525
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
9300 6225 10350 6225 10350 6525 9300 6525 9300 6225
@ -173,10 +168,35 @@ Single
9300 5850 10350 5850 10350 6150 9300 6150 9300 5850
4 0 0 50 -1 0 12 0.0000 4 135 825 9375 6075 EAP-AKA\001
-6
6 8175 6975 9675 7275
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
8100 6975 10425 6975 10425 4425 8100 4425 8100 6975
8175 6975 9675 6975 9675 7275 8175 7275 8175 6975
4 0 0 50 -1 0 12 0.0000 4 135 1365 8250 7200 EAP-MSCHAPv2\001
-6
6 9300 6600 10350 6900
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
9300 6600 10350 6600 10350 6900 9300 6900 9300 6600
4 0 0 50 -1 0 12 0.0000 4 135 870 9375 6825 EAP-FAST\001
-6
6 8175 6600 9225 6900
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
8175 6600 9225 6600 9225 6900 8175 6900 8175 6600
4 0 0 50 -1 0 12 0.0000 4 135 795 8250 6825 EAP-PAX\001
-6
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
8100 7350 10425 7350 10425 4425 8100 4425 8100 7350
4 0 0 50 -1 0 12 0.0000 4 135 1050 8700 4650 EAP methods\001
-6
6 2775 5025 4050 5325
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
2775 5025 4050 5025 4050 5325 2775 5325 2775 5025
4 0 0 50 -1 0 12 0.0000 4 135 990 2925 5250 driver events\001
-6
6 2775 3150 4050 3450
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
2775 3150 4050 3150 4050 3450 2775 3450 2775 3150
4 0 0 50 -1 0 12 0.0000 4 180 990 2925 3375 configuration\001
-6
2 1 1 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 2
1275 4200 1875 4200
2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
@ -213,9 +233,15 @@ Single
1500 2100 10800 2100 10800 7500 1500 7500 1500 2100
2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
9900 4425 9900 3300
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 1
4350 3900
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
4350 3900 4050 3450
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
4350 4425 4050 5025
4 0 0 50 -1 0 12 0.0000 4 135 915 375 3975 EAPOL and\001
4 0 0 50 -1 0 12 0.0000 4 180 630 375 4200 pre-auth\001
4 0 0 50 -1 0 12 0.0000 4 180 810 375 4425 ethertypes\001
4 0 0 50 -1 0 12 0.0000 4 135 1050 375 4650 from/to kernel\001
4 0 0 50 -1 0 12 0.0000 4 135 1920 3675 1875 frontend control interface\001
4 0 0 50 -1 2 14 0.0000 4 195 1425 1637 2371 wpa_supplicant\001
4 0 0 50 -1 2 14 0.0000 4 210 1440 1637 2371 wpa_supplicant\001

View file

@ -1,13 +1,23 @@
/*
* WPA Supplicant - driver interface definition
* Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef DRIVER_H
#define DRIVER_H
#define WPA_SUPPLICANT_DRIVER_VERSION 2
typedef enum { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP } wpa_alg;
typedef enum { CIPHER_NONE, CIPHER_WEP40, CIPHER_TKIP, CIPHER_CCMP,
CIPHER_WEP104 } wpa_cipher;
typedef enum { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE,
KEY_MGMT_802_1X_NO_WPA, KEY_MGMT_WPA_NONE } wpa_key_mgmt;
#include "defs.h"
#define AUTH_ALG_OPEN_SYSTEM 0x01
#define AUTH_ALG_SHARED_KEY 0x02
@ -16,7 +26,31 @@ typedef enum { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE,
#define IEEE80211_MODE_INFRA 0
#define IEEE80211_MODE_IBSS 1
#define IEEE80211_CAP_ESS 0x0001
#define IEEE80211_CAP_IBSS 0x0002
#define IEEE80211_CAP_PRIVACY 0x0010
#define SSID_MAX_WPA_IE_LEN 40
/**
* struct wpa_scan_result - Scan results
* @bssid: BSSID
* @ssid: SSID
* @ssid_len: length of the ssid
* @wpa_ie: WPA IE
* @wpa_ie_len: length of the wpa_ie
* @rsn_ie: RSN IE
* @rsn_ie_len: length of the RSN IE
* @freq: frequency of the channel in MHz (e.g., 2412 = channel 1)
* @caps: capability information field in host byte order
* @qual: signal quality
* @noise: noise level
* @level: signal level
* @maxrate: maximum supported rate
*
* This structure is used as a generic format for scan results from the
* driver. Each driver interface implementation is responsible for converting
* the driver or OS specific scan results into this format.
*/
struct wpa_scan_result {
u8 bssid[ETH_ALEN];
u8 ssid[32];
@ -25,40 +59,57 @@ struct wpa_scan_result {
size_t wpa_ie_len;
u8 rsn_ie[SSID_MAX_WPA_IE_LEN];
size_t rsn_ie_len;
int freq; /* MHz */
int caps; /* e.g. privacy */
int qual; /* signal quality */
int freq;
u16 caps;
int qual;
int noise;
int level;
int maxrate;
};
/* Parameters for associate driver_ops. */
/**
* struct wpa_driver_associate_params - Association parameters
* Data for struct wpa_driver_ops::associate().
*/
struct wpa_driver_associate_params {
/* BSSID of the selected AP */
/**
* bssid - BSSID of the selected AP
* This can be %NULL, if ap_scan=2 mode is used and the driver is
* responsible for selecting with which BSS to associate. */
const u8 *bssid;
/* The selected SSID and its length in bytes */
/**
* ssid - The selected SSID
*/
const u8 *ssid;
size_t ssid_len;
/* frequency that the selected AP is using (in MHz as
* reported in the scan results) */
/**
* freq - Frequency of the channel the selected AP is using
* Frequency that the selected AP is using (in MHz as
* reported in the scan results)
*/
int freq;
/* WPA information element to be included in (Re)Association
/**
* wpa_ie - WPA information element for (Re)Association Request
* WPA information element to be included in (Re)Association
* Request (including information element id and length). Use
* of this WPA IE is optional. If the driver generates the WPA
* IE, it can use @pairwise_suite, @group_suite, and
* @key_mgmt_suite to select proper algorithms. In this case,
* IE, it can use pairwise_suite, group_suite, and
* key_mgmt_suite to select proper algorithms. In this case,
* the driver has to notify wpa_supplicant about the used WPA
* IE by generating an event that the interface code will
* convert into EVENT_ASSOCINFO data (see wpa_supplicant.h).
* When using WPA2/IEEE 802.11i, @wpa_ie is used for RSN IE
* When using WPA2/IEEE 802.11i, wpa_ie is used for RSN IE
* instead. The driver can determine which version is used by
* looking at the first byte of the IE (0xdd for WPA, 0x30 for
* WPA2/RSN). @wpa_ie_len: length of the @wpa_ie */
* WPA2/RSN).
*/
const u8 *wpa_ie;
/**
* wpa_ie_len - length of the wpa_ie
*/
size_t wpa_ie_len;
/* The selected pairwise/group cipher and key management
@ -67,10 +118,21 @@ struct wpa_driver_associate_params {
wpa_cipher group_suite;
wpa_key_mgmt key_mgmt_suite;
int auth_alg; /* bit field of AUTH_ALG_* */
int mode; /* IEEE80211_MODE_* */
/**
* auth_alg - Allowed authentication algorithms
* Bit field of AUTH_ALG_*
*/
int auth_alg;
/**
* mode - Operation mode (infra/ibss) IEEE80211_MODE_*
*/
int mode;
};
/**
* struct wpa_driver_capa - Driver capability information
*/
struct wpa_driver_capa {
#define WPA_DRIVER_CAPA_KEY_MGMT_WPA 0x00000001
#define WPA_DRIVER_CAPA_KEY_MGMT_WPA2 0x00000002
@ -97,33 +159,40 @@ struct wpa_driver_capa {
};
/**
* struct wpa_driver_ops - Driver interface API definition
*
* This structure defines the API that each driver interface needs to implement
* for core wpa_supplicant code. All driver specific functionality is captured
* in this wrapper.
*/
struct wpa_driver_ops {
/* name of the driver interface */
/** Name of the driver interface */
const char *name;
/* one line description of the driver interface */
/** One line description of the driver interface */
const char *desc;
/**
* get_bssid - get the current BSSID
* get_bssid - Get the current BSSID
* @priv: private driver interface data
* @bssid: buffer for BSSID (ETH_ALEN = 6 bytes)
*
* Returns: 0 on success, -1 on failure
*
* Query kernel driver for the current BSSID and copy it to @bssid.
* Setting @bssid to 00:00:00:00:00:00 is recommended if the STA is not
* Query kernel driver for the current BSSID and copy it to bssid.
* Setting bssid to 00:00:00:00:00:00 is recommended if the STA is not
* associated.
*/
int (*get_bssid)(void *priv, u8 *bssid);
/**
* get_ssid - get the current SSID
* get_ssid - Get the current SSID
* @priv: private driver interface data
* @ssid: buffer for SSID (at least 32 bytes)
*
* Returns: length of the SSID on success, -1 on failure
* Returns: Length of the SSID on success, -1 on failure
*
* Query kernel driver for the current SSID and copy it to @ssid.
* Query kernel driver for the current SSID and copy it to ssid.
* Returning zero is recommended if the STA is not associated.
*
* Note: SSID is an array of octets, i.e., it is not nul terminated and
@ -134,35 +203,44 @@ struct wpa_driver_ops {
int (*get_ssid)(void *priv, u8 *ssid);
/**
* set_wpa - enable/disable WPA support
* set_wpa - Enable/disable WPA support (OBSOLETE)
* @priv: private driver interface data
* @enabled: 1 = enable, 0 = disable
*
* Returns: 0 on success, -1 on failure
*
* Note: This function is included for backwards compatibility. This is
* called only just after init and just before deinit, so these
* functions can be used to implement same functionality and the driver
* interface need not define this function.
*
* Configure the kernel driver to enable/disable WPA support. This may
* be empty function, if WPA support is always enabled. Common
* configuration items are WPA IE (clearing it when WPA support is
* disabled), Privacy flag for capability field, roaming mode (need to
* allow wpa_supplicant to control roaming).
* disabled), Privacy flag configuration for capability field (note:
* this the value need to set in associate handler to allow plaintext
* mode to be used) when trying to associate with, roaming mode (can
* allow wpa_supplicant to control roaming if ap_scan=1 is used;
* however, drivers can also implement roaming if desired, especially
* ap_scan=2 mode is used for this).
*/
int (*set_wpa)(void *priv, int enabled);
/**
* set_key - configure encryption key
* set_key - Configure encryption key
* @priv: private driver interface data
* @alg: encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP,
* %WPA_ALG_TKIP, %WPA_ALG_CCMP); %WPA_ALG_NONE clears the key.
* @addr: address of the peer STA or ff:ff:ff:ff:ff:ff for
* broadcast/default keys
* @key_idx: key index (0..3), always 0 for unicast keys
* @key_idx: key index (0..3), usually 0 for unicast keys
* @set_tx: configure this key as the default Tx key (only used when
* driver does not support separate unicast/individual key
* @seq: sequence number/packet number, @seq_len octets, the next
* @seq: sequence number/packet number, seq_len octets, the next
* packet number to be used for in replay protection; configured
* for Rx keys (in most cases, this is only used with broadcast
* keys and set to zero for unicast keys)
* @seq_len: length of the @seq, depends on the algorithm:
* @seq_len: length of the seq, depends on the algorithm:
* TKIP: 6 octets, CCMP: 6 octets
* @key: key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key,
* 8-byte Rx Mic Key
@ -173,25 +251,33 @@ struct wpa_driver_ops {
*
* Configure the given key for the kernel driver. If the driver
* supports separate individual keys (4 default keys + 1 individual),
* @addr can be used to determine whether the key is default or
* addr can be used to determine whether the key is default or
* individual. If only 4 keys are supported, the default key with key
* index 0 is used as the individual key. STA must be configured to use
* it as the default Tx key (@set_tx is set) and accept Rx for all the
* it as the default Tx key (set_tx is set) and accept Rx for all the
* key indexes. In most cases, WPA uses only key indexes 1 and 2 for
* broadcast keys, so key index 0 is available for this kind of
* configuration.
*
* Please note that TKIP keys include separate TX and RX MIC keys and
* some drivers may expect them in different order than wpa_supplicant
* is using. If the TX/RX keys are swapped, all TKIP encrypted packets
* will tricker Michael MIC errors. This can be fixed by changing the
* order of MIC keys by swapping te bytes 16..23 and 24..31 of the key
* in driver_*.c set_key() implementation, see driver_ndis.c for an
* example on how this can be done.
*/
int (*set_key)(void *priv, wpa_alg alg, const u8 *addr,
int key_idx, int set_tx, const u8 *seq, size_t seq_len,
const u8 *key, size_t key_len);
/**
* init - initialize driver interface
* init - Initialize driver interface
* @ctx: context to be used when calling wpa_supplicant functions,
* e.g., wpa_supplicant_event()
* @ifname: interface name, e.g., wlan0
*
* Return: pointer to private data, %NULL on failure
* Returns: Pointer to private data, %NULL on failure
*
* Initialize driver interface, including event processing for kernel
* driver events (e.g., associated, scan results, Michael MIC failure).
@ -211,9 +297,8 @@ struct wpa_driver_ops {
void * (*init)(void *ctx, const char *ifname);
/**
* deinit - deinitialize driver interface
* @priv: pointer to private data (from matching
* wpa_driver_events_init())
* deinit - Deinitialize driver interface
* @priv: private driver interface data from init()
*
* Shut down driver interface and processing of driver events. Free
* private data buffer if one was allocated in init() handler.
@ -221,11 +306,23 @@ struct wpa_driver_ops {
void (*deinit)(void *priv);
/**
* set_countermeasures - enable/disable TKIP countermeasures
* set_param - Set driver configuration parameters
* @priv: private driver interface data from init()
* @param: driver specific configuration parameters
*
* Returns: 0 on success, -1 on failure
*
* Optional handler for notifying driver interface about configuration
* parameters (driver_param).
*/
int (*set_param)(void *priv, const char *param);
/**
* set_countermeasures - Enable/disable TKIP countermeasures
* @priv: private driver interface data
* @enabled: 1 = countermeasures enabled, 0 = disabled
*
* Return: 0 on success, -1 on failure
* Returns: 0 on success, -1 on failure
*
* Configure TKIP countermeasures. When these are enabled, the driver
* should drop all received and queued frames that are using TKIP.
@ -233,11 +330,11 @@ struct wpa_driver_ops {
int (*set_countermeasures)(void *priv, int enabled);
/**
* set_drop_unencrypted - enable/disable unencrypted frame filtering
* set_drop_unencrypted - Enable/disable unencrypted frame filtering
* @priv: private driver interface data
* @enabled: 1 = unencrypted Tx/Rx frames will be dropped, 0 = disabled
*
* Return: 0 on success, -1 on failure
* Returns: 0 on success, -1 on failure
*
* Configure the driver to drop all non-EAPOL frames (both receive and
* transmit paths). Unencrypted EAPOL frames (ethertype 0x888e) must
@ -246,14 +343,14 @@ struct wpa_driver_ops {
int (*set_drop_unencrypted)(void *priv, int enabled);
/**
* scan - request the driver to initiate scan
* scan - Request the driver to initiate scan
* @priv: private driver interface data
* @ssid: specific SSID to scan for (ProbeReq) or %NULL to scan for
* all SSIDs (either active scan with broadcast SSID or passive
* scan
* @ssid_len: length of the SSID
*
* Return: 0 on success, -1 on failure
* Returns: 0 on success, -1 on failure
*
* Once the scan results are ready, the driver should report scan
* results event for wpa_supplicant which will eventually request the
@ -262,14 +359,15 @@ struct wpa_driver_ops {
int (*scan)(void *priv, const u8 *ssid, size_t ssid_len);
/**
* get_scan_results - fetch the latest scan results
* get_scan_results - Fetch the latest scan results
* @priv: private driver interface data
* @results: pointer to buffer for scan results
* @max_size: maximum number of entries (buffer size)
*
* Return: number of scan result entries used on success, -1 on failure
* Returns: Number of scan result entries used on success, -1 on
* failure
*
* If scan results include more than @max_size BSSes, @max_size will be
* If scan results include more than max_size BSSes, max_size will be
* returned and the remaining entries will not be included in the
* buffer.
*/
@ -278,39 +376,39 @@ struct wpa_driver_ops {
size_t max_size);
/**
* deauthenticate - request driver to deauthenticate
* deauthenticate - Request driver to deauthenticate
* @priv: private driver interface data
* @addr: peer address (BSSID of the AP)
* @reason_code: 16-bit reason code to be sent in the deauthentication
* frame
*
* Return: 0 on success, -1 on failure
* Returns: 0 on success, -1 on failure
*/
int (*deauthenticate)(void *priv, const u8 *addr, int reason_code);
/**
* disassociate - request driver to disassociate
* disassociate - Request driver to disassociate
* @priv: private driver interface data
* @addr: peer address (BSSID of the AP)
* @reason_code: 16-bit reason code to be sent in the disassociation
* frame
*
* Return: 0 on success, -1 on failure
* Returns: 0 on success, -1 on failure
*/
int (*disassociate)(void *priv, const u8 *addr, int reason_code);
/**
* associate - request driver to associate
* associate - Request driver to associate
* @priv: private driver interface data
* @params: association parameters
*
* Return: 0 on success, -1 on failure
* Returns: 0 on success, -1 on failure
*/
int (*associate)(void *priv,
struct wpa_driver_associate_params *params);
/**
* set_auth_alg - set IEEE 802.11 authentication algorithm
* set_auth_alg - Set IEEE 802.11 authentication algorithm
* @priv: private driver interface data
* @auth_alg: bit field of AUTH_ALG_*
*
@ -326,43 +424,43 @@ struct wpa_driver_ops {
* associate() params, so set_auth_alg may not be needed in case of
* most drivers.
*
* Return: 0 on success, -1 on failure
* Returns: 0 on success, -1 on failure
*/
int (*set_auth_alg)(void *priv, int auth_alg);
/**
* add_pmkid - add PMKSA cache entry to the driver
* add_pmkid - Add PMKSA cache entry to the driver
* @priv: private driver interface data
* @bssid: BSSID for the PMKSA cache entry
* @pmkid: PMKID for the PMKSA cache entry
*
* Return: 0 on success, -1 on failure
* Returns: 0 on success, -1 on failure
*
* This function is called when a new PMK is received, as a result of
* either normal authentication or RSN pre-authentication.
*
* If the driver generates RSN IE, i.e., it does not use @wpa_ie in
* If the driver generates RSN IE, i.e., it does not use wpa_ie in
* associate(), add_pmkid() can be used to add new PMKSA cache entries
* in the driver. If the driver uses @wpa_ie from wpa_supplicant, this
* in the driver. If the driver uses wpa_ie from wpa_supplicant, this
* driver_ops function does not need to be implemented. Likewise, if
* the driver does not support WPA, this function is not needed.
*/
int (*add_pmkid)(void *priv, const u8 *bssid, const u8 *pmkid);
/**
* remove_pmkid - remove PMKSA cache entry to the driver
* remove_pmkid - Remove PMKSA cache entry to the driver
* @priv: private driver interface data
* @bssid: BSSID for the PMKSA cache entry
* @pmkid: PMKID for the PMKSA cache entry
*
* Return: 0 on success, -1 on failure
* Returns: 0 on success, -1 on failure
*
* This function is called when the supplicant drops a PMKSA cache
* entry for any reason.
*
* If the driver generates RSN IE, i.e., it does not use @wpa_ie in
* If the driver generates RSN IE, i.e., it does not use wpa_ie in
* associate(), remove_pmkid() can be used to synchronize PMKSA caches
* between the driver and wpa_supplicant. If the driver uses @wpa_ie
* between the driver and wpa_supplicant. If the driver uses wpa_ie
* from wpa_supplicant, this driver_ops function does not need to be
* implemented. Likewise, if the driver does not support WPA, this
* function is not needed.
@ -370,17 +468,17 @@ struct wpa_driver_ops {
int (*remove_pmkid)(void *priv, const u8 *bssid, const u8 *pmkid);
/**
* flush_pmkid - flush PMKSA cache
* flush_pmkid - Flush PMKSA cache
* @priv: private driver interface data
*
* Return: 0 on success, -1 on failure
* Returns: 0 on success, -1 on failure
*
* This function is called when the supplicant drops all PMKSA cache
* entries for any reason.
*
* If the driver generates RSN IE, i.e., it does not use @wpa_ie in
* If the driver generates RSN IE, i.e., it does not use wpa_ie in
* associate(), remove_pmkid() can be used to synchronize PMKSA caches
* between the driver and wpa_supplicant. If the driver uses @wpa_ie
* between the driver and wpa_supplicant. If the driver uses wpa_ie
* from wpa_supplicant, this driver_ops function does not need to be
* implemented. Likewise, if the driver does not support WPA, this
* function is not needed.
@ -388,17 +486,17 @@ struct wpa_driver_ops {
int (*flush_pmkid)(void *priv);
/**
* flush_pmkid - flush PMKSA cache
* flush_pmkid - Flush PMKSA cache
* @priv: private driver interface data
*
* Return: 0 on success, -1 on failure
* Returns: 0 on success, -1 on failure
*
* Get driver/firmware/hardware capabilities.
*/
int (*get_capa)(void *priv, struct wpa_driver_capa *capa);
/**
* poll - poll driver for association information
* poll - Poll driver for association information
* @priv: private driver interface data
*
* This is an option callback that can be used when the driver does not
@ -412,25 +510,50 @@ struct wpa_driver_ops {
void (*poll)(void *priv);
/**
* get_ifname - get interface name
* get_ifname - Get interface name
* @priv: private driver interface data
*
* Returns: Pointer to the interface name. This can differ from the
* interface name used in init() call.
*
* This optional function can be used to allow the driver interface to
* replace the interface name with something else, e.g., based on an
* interface mapping from a more descriptive name.
*
* Returns a pointer to the interface name. This can differ from the
* interface name used in init() call.
*/
const char * (*get_ifname)(void *priv);
/**
* get_mac_addr - get own MAC address
* get_mac_addr - Get own MAC address
* @priv: private driver interface data
*
* Returns: Pointer to own MAC address or %NULL on failure
*
* This optional function can be used to get the own MAC address of the
* device from the driver interface code. This is only needed if the
* l2_packet implementation for the OS does not provide easy access to
* a MAC address. */
const u8 * (*get_mac_addr)(void *priv);
/**
* send_eapol - Optional function for sending EAPOL packets
* @priv: private driver interface data
* @dest: Destination MAC address
* @proto: Ethertype
* @data: EAPOL packet starting with IEEE 802.1X header
* @data_len: Size of the EAPOL packet
*
* Returns: 0 on success, -1 on failure
*
* This optional function can be used to override l2_packet operations
* with driver specific functionality. If this function pointer is set,
* l2_packet module is not used at all and the driver interface code is
* responsible for receiving and sending all EAPOL packets. The
* received EAPOL packets are sent to core code by calling
* wpa_supplicant_rx_eapol(). The driver interface is required to
* implement get_mac_addr() handler if send_eapol() is used.
*/
int (*send_eapol)(void *priv, const u8 *dest, u16 proto,
const u8 *data, size_t data_len);
};
#endif /* DRIVER_H */

View file

@ -0,0 +1,153 @@
/*
* WPA Supplicant - driver interaction with Linux Host AP driver
* Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef HOSTAP_DRIVER_H
#define HOSTAP_DRIVER_H
#define PRISM2_IOCTL_PRISM2_PARAM (SIOCIWFIRSTPRIV + 0)
#define PRISM2_IOCTL_RESET (SIOCIWFIRSTPRIV + 6)
#define PRISM2_IOCTL_HOSTAPD (SIOCDEVPRIVATE + 14)
/* PRISM2_IOCTL_PRISM2_PARAM ioctl() subtypes: */
enum {
/* PRISM2_PARAM_PTYPE = 1, */ /* REMOVED 2003-10-22 */
PRISM2_PARAM_TXRATECTRL = 2,
PRISM2_PARAM_BEACON_INT = 3,
PRISM2_PARAM_PSEUDO_IBSS = 4,
PRISM2_PARAM_ALC = 5,
/* PRISM2_PARAM_TXPOWER = 6, */ /* REMOVED 2003-10-22 */
PRISM2_PARAM_DUMP = 7,
PRISM2_PARAM_OTHER_AP_POLICY = 8,
PRISM2_PARAM_AP_MAX_INACTIVITY = 9,
PRISM2_PARAM_AP_BRIDGE_PACKETS = 10,
PRISM2_PARAM_DTIM_PERIOD = 11,
PRISM2_PARAM_AP_NULLFUNC_ACK = 12,
PRISM2_PARAM_MAX_WDS = 13,
PRISM2_PARAM_AP_AUTOM_AP_WDS = 14,
PRISM2_PARAM_AP_AUTH_ALGS = 15,
PRISM2_PARAM_MONITOR_ALLOW_FCSERR = 16,
PRISM2_PARAM_HOST_ENCRYPT = 17,
PRISM2_PARAM_HOST_DECRYPT = 18,
PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX = 19,
PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX = 20,
PRISM2_PARAM_HOST_ROAMING = 21,
PRISM2_PARAM_BCRX_STA_KEY = 22,
PRISM2_PARAM_IEEE_802_1X = 23,
PRISM2_PARAM_ANTSEL_TX = 24,
PRISM2_PARAM_ANTSEL_RX = 25,
PRISM2_PARAM_MONITOR_TYPE = 26,
PRISM2_PARAM_WDS_TYPE = 27,
PRISM2_PARAM_HOSTSCAN = 28,
PRISM2_PARAM_AP_SCAN = 29,
PRISM2_PARAM_ENH_SEC = 30,
PRISM2_PARAM_IO_DEBUG = 31,
PRISM2_PARAM_BASIC_RATES = 32,
PRISM2_PARAM_OPER_RATES = 33,
PRISM2_PARAM_HOSTAPD = 34,
PRISM2_PARAM_HOSTAPD_STA = 35,
PRISM2_PARAM_WPA = 36,
PRISM2_PARAM_PRIVACY_INVOKED = 37,
PRISM2_PARAM_TKIP_COUNTERMEASURES = 38,
PRISM2_PARAM_DROP_UNENCRYPTED = 39,
PRISM2_PARAM_SCAN_CHANNEL_MASK = 40,
};
/* PRISM2_IOCTL_HOSTAPD ioctl() cmd: */
enum {
PRISM2_HOSTAPD_FLUSH = 1,
PRISM2_HOSTAPD_ADD_STA = 2,
PRISM2_HOSTAPD_REMOVE_STA = 3,
PRISM2_HOSTAPD_GET_INFO_STA = 4,
/* REMOVED: PRISM2_HOSTAPD_RESET_TXEXC_STA = 5, */
PRISM2_SET_ENCRYPTION = 6,
PRISM2_GET_ENCRYPTION = 7,
PRISM2_HOSTAPD_SET_FLAGS_STA = 8,
PRISM2_HOSTAPD_GET_RID = 9,
PRISM2_HOSTAPD_SET_RID = 10,
PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR = 11,
PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12,
PRISM2_HOSTAPD_MLME = 13,
PRISM2_HOSTAPD_SCAN_REQ = 14,
PRISM2_HOSTAPD_STA_CLEAR_STATS = 15,
};
#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024
#define PRISM2_HOSTAPD_RID_HDR_LEN \
((int) (&((struct prism2_hostapd_param *) 0)->u.rid.data))
#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
((int) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data))
/* Maximum length for algorithm names (-1 for nul termination) used in ioctl()
*/
#define HOSTAP_CRYPT_ALG_NAME_LEN 16
struct prism2_hostapd_param {
u32 cmd;
u8 sta_addr[ETH_ALEN];
union {
struct {
u16 aid;
u16 capability;
u8 tx_supp_rates;
} add_sta;
struct {
u32 inactive_sec;
} get_info_sta;
struct {
u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN];
u32 flags;
u32 err;
u8 idx;
u8 seq[8]; /* sequence counter (set: RX, get: TX) */
u16 key_len;
u8 key[0];
} crypt;
struct {
u32 flags_and;
u32 flags_or;
} set_flags_sta;
struct {
u16 rid;
u16 len;
u8 data[0];
} rid;
struct {
u8 len;
u8 data[0];
} generic_elem;
struct {
#define MLME_STA_DEAUTH 0
#define MLME_STA_DISASSOC 1
u16 cmd;
u16 reason_code;
} mlme;
struct {
u8 ssid_len;
u8 ssid[32];
} scan_req;
} u;
};
#define HOSTAP_CRYPT_FLAG_SET_TX_KEY 0x01
#define HOSTAP_CRYPT_FLAG_PERMANENT 0x02
#define HOSTAP_CRYPT_ERR_UNKNOWN_ALG 2
#define HOSTAP_CRYPT_ERR_UNKNOWN_ADDR 3
#define HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED 4
#define HOSTAP_CRYPT_ERR_KEY_SET_FAILED 5
#define HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED 6
#define HOSTAP_CRYPT_ERR_CARD_CONF_FAILED 7
#endif /* HOSTAP_DRIVER_H */

View file

@ -393,6 +393,20 @@ static int wpa_driver_ndis_get_bssid(void *priv, u8 *bssid)
{
struct wpa_driver_ndis_data *drv = priv;
if (drv->wired) {
/*
* Report PAE group address as the "BSSID" for wired
* connection.
*/
bssid[0] = 0x01;
bssid[1] = 0x80;
bssid[2] = 0xc2;
bssid[3] = 0x00;
bssid[4] = 0x00;
bssid[5] = 0x03;
return 0;
}
return ndis_get_oid(drv, OID_802_11_BSSID, bssid, ETH_ALEN) < 0 ?
-1 : 0;
}
@ -406,8 +420,13 @@ static int wpa_driver_ndis_get_ssid(void *priv, u8 *ssid)
int res;
res = ndis_get_oid(drv, OID_802_11_SSID, (char *) &buf, sizeof(buf));
if (!res) {
if (res < 4) {
wpa_printf(MSG_DEBUG, "NDIS: Failed to get SSID");
if (drv->wired) {
wpa_printf(MSG_DEBUG, "NDIS: Allow get_ssid failure "
"with a wired interface");
return 0;
}
return -1;
}
memcpy(ssid, buf.Ssid, buf.SsidLength);
@ -423,6 +442,12 @@ static int wpa_driver_ndis_set_ssid(struct wpa_driver_ndis_data *drv,
memset(&buf, 0, sizeof(buf));
buf.SsidLength = ssid_len;
memcpy(buf.Ssid, ssid, ssid_len);
/*
* Make sure radio is marked enabled here so that scan request will not
* force SSID to be changed to a random one in order to enable radio at
* that point.
*/
drv->radio_enabled = 1;
return ndis_set_oid(drv, OID_802_11_SSID, (char *) &buf, sizeof(buf));
}
@ -562,7 +587,7 @@ static int wpa_driver_ndis_get_scan_results(void *priv,
memcpy(results[i].ssid, bss->Ssid.Ssid, bss->Ssid.SsidLength);
results[i].ssid_len = bss->Ssid.SsidLength;
if (bss->Privacy)
results[i].caps = 1; /* FIX? */
results[i].caps |= IEEE80211_CAP_PRIVACY;
results[i].level = (int) bss->Rssi;
results[i].freq = bss->Configuration.DSConfig / 1000;
for (j = 0; j < sizeof(bss->SupportedRates); j++) {
@ -574,6 +599,8 @@ static int wpa_driver_ndis_get_scan_results(void *priv,
}
wpa_driver_ndis_get_ies(&results[i], bss->IEs, bss->IELength);
pos += bss->Length;
if (pos > (char *) b + blen)
break;
}
free(b);
@ -928,10 +955,12 @@ static int wpa_driver_ndis_flush_pmkid(void *priv)
static int wpa_driver_ndis_get_associnfo(struct wpa_driver_ndis_data *drv)
{
char buf[512];
char buf[512], *pos;
NDIS_802_11_ASSOCIATION_INFORMATION *ai;
int len;
int len, i;
union wpa_event_data data;
NDIS_802_11_BSSID_LIST_EX *b;
size_t blen;
len = ndis_get_oid(drv, OID_802_11_ASSOCIATION_INFORMATION, buf,
sizeof(buf));
@ -990,8 +1019,47 @@ static int wpa_driver_ndis_get_associnfo(struct wpa_driver_ndis_data *drv)
data.assoc_info.req_ies_len = ai->RequestIELength;
data.assoc_info.resp_ies = buf + ai->OffsetResponseIEs;
data.assoc_info.resp_ies_len = ai->ResponseIELength;
blen = 65535;
b = malloc(blen);
if (b == NULL)
goto skip_scan_results;
memset(b, 0, blen);
len = ndis_get_oid(drv, OID_802_11_BSSID_LIST, (char *) b, blen);
if (len < 0) {
wpa_printf(MSG_DEBUG, "NDIS: failed to get scan results");
free(b);
b = NULL;
goto skip_scan_results;
}
wpa_printf(MSG_DEBUG, "NDIS: %d BSSID items to process for AssocInfo",
(unsigned int) b->NumberOfItems);
pos = (char *) &b->Bssid[0];
for (i = 0; i < b->NumberOfItems; i++) {
NDIS_WLAN_BSSID_EX *bss = (NDIS_WLAN_BSSID_EX *) pos;
if (memcmp(drv->bssid, bss->MacAddress, ETH_ALEN) == 0 &&
bss->IELength > sizeof(NDIS_802_11_FIXED_IEs)) {
data.assoc_info.beacon_ies =
((u8 *) bss->IEs) +
sizeof(NDIS_802_11_FIXED_IEs);
data.assoc_info.beacon_ies_len =
bss->IELength - sizeof(NDIS_802_11_FIXED_IEs);
wpa_hexdump(MSG_MSGDUMP, "NDIS: Beacon IEs",
data.assoc_info.beacon_ies,
data.assoc_info.beacon_ies_len);
break;
}
pos += bss->Length;
if (pos > (char *) b + blen)
break;
}
skip_scan_results:
wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &data);
free(b);
return 0;
}
@ -1001,6 +1069,9 @@ static void wpa_driver_ndis_poll_timeout(void *eloop_ctx, void *timeout_ctx)
struct wpa_driver_ndis_data *drv = eloop_ctx;
u8 bssid[ETH_ALEN];
if (drv->wired)
return;
if (wpa_driver_ndis_get_bssid(drv, bssid)) {
/* Disconnected */
if (memcmp(drv->bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN)
@ -1339,39 +1410,63 @@ static const u8 * wpa_driver_ndis_get_mac_addr(void *priv)
static int wpa_driver_ndis_get_names(struct wpa_driver_ndis_data *drv)
{
PTSTR names, pos;
PTSTR names, pos, pos2;
ULONG len;
BOOLEAN res;
const int MAX_ADAPTERS = 16;
const int MAX_ADAPTERS = 32;
char *name[MAX_ADAPTERS];
char *desc[MAX_ADAPTERS];
int num_name, num_desc, i, found_name, found_desc;
size_t dlen;
len = 1024;
wpa_printf(MSG_DEBUG, "NDIS: Packet.dll version: %s",
PacketGetVersion());
len = 8192;
names = malloc(len);
if (names == NULL)
return -1;
memset(names, 0, len);
res = PacketGetAdapterNames(names, &len);
if (!res && len > 1024) {
if (!res && len > 8192) {
free(names);
names = malloc(len);
if (names == NULL)
return -1;
memset(names, 0, len);
res = PacketGetAdapterNames(names, &len);
if (!res) {
free(names);
return -1;
}
}
if (!res) {
wpa_printf(MSG_ERROR, "NDIS: Failed to get adapter list "
"(PacketGetAdapterNames)");
free(names);
return -1;
}
/* wpa_hexdump_ascii(MSG_DEBUG, "NDIS: AdapterNames", names, len); */
if (names[0] && names[1] == '\0' && names[2] && names[3] == '\0') {
wpa_printf(MSG_DEBUG, "NDIS: Looks like adapter names are in "
"UNICODE");
/* Convert to ASCII */
pos2 = pos = names;
while (pos2 < names + len) {
if (pos2[0] == '\0' && pos2[1] == '\0' &&
pos2[2] == '\0' && pos2[3] == '\0') {
pos2 += 4;
break;
}
*pos++ = pos2[0];
pos2 += 2;
}
memcpy(pos + 2, names, pos - names);
pos += 2;
} else
pos = names;
num_name = 0;
pos = names;
while (pos < names + len) {
name[num_name] = pos;
while (*pos && pos < names + len)
@ -1420,6 +1515,13 @@ static int wpa_driver_ndis_get_names(struct wpa_driver_ndis_data *drv)
}
}
/*
* Windows 98 with Packet.dll 3.0 alpha3 does not include adapter
* descriptions. Fill in dummy descriptors to work around this.
*/
while (num_desc < num_name)
desc[num_desc++] = "dummy description";
if (num_name != num_desc) {
wpa_printf(MSG_DEBUG, "NDIS: mismatch in adapter name and "
"description counts (%d != %d)",
@ -1537,6 +1639,13 @@ static void * wpa_driver_ndis_init(void *ctx, const char *ifname)
"OID_802_11_INFRASTRUCTURE_MODE (%d)",
(int) mode);
/* Try to continue anyway */
if (!drv->has_capability && drv->capa.enc == 0) {
wpa_printf(MSG_DEBUG, "NDIS: Driver did not provide "
"any wireless capabilities - assume it is "
"a wired interface");
drv->wired = 1;
}
}
return drv;
@ -1565,7 +1674,7 @@ static void wpa_driver_ndis_deinit(void *priv)
}
struct wpa_driver_ops wpa_driver_ndis_ops = {
const struct wpa_driver_ops wpa_driver_ndis_ops = {
.name = "ndis",
.desc = "Windows NDIS driver",
.init = wpa_driver_ndis_init,

View file

@ -1,3 +1,17 @@
/*
* WPA Supplicant - Windows/NDIS driver interface
* Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef DRIVER_NDIS_H
#define DRIVER_NDIS_H
@ -21,6 +35,7 @@ struct wpa_driver_ndis_data {
struct ndis_pmkid_entry *pmkid;
int event_sock;
char *adapter_desc;
int wired;
};
#endif /* DRIVER_NDIS_H */

View file

@ -0,0 +1,271 @@
/*
* WPA Supplicant - wired Ethernet driver interface
* Copyright (c) 2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netpacket/packet.h>
#include <net/if.h>
#include "common.h"
#include "driver.h"
#include "wpa_supplicant.h"
static const u8 pae_group_addr[ETH_ALEN] =
{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
struct wpa_driver_wired_data {
void *ctx;
int pf_sock;
char ifname[IFNAMSIZ + 1];
int membership, multi, iff_allmulti, iff_up;
};
static int wpa_driver_wired_set_wpa(void *priv, int enabled)
{
return 0;
}
static int wpa_driver_wired_get_ssid(void *priv, u8 *ssid)
{
ssid[0] = 0;
return 0;
}
static int wpa_driver_wired_get_bssid(void *priv, u8 *bssid)
{
/* Report PAE group address as the "BSSID" for wired connection. */
memcpy(bssid, pae_group_addr, ETH_ALEN);
return 0;
}
static int wpa_driver_wired_get_ifflags(const char *ifname, int *flags)
{
struct ifreq ifr;
int s;
s = socket(PF_INET, SOCK_DGRAM, 0);
if (s < 0) {
perror("socket");
return -1;
}
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
perror("ioctl[SIOCGIFFLAGS]");
close(s);
return -1;
}
close(s);
*flags = ifr.ifr_flags & 0xffff;
return 0;
}
static int wpa_driver_wired_set_ifflags(const char *ifname, int flags)
{
struct ifreq ifr;
int s;
s = socket(PF_INET, SOCK_DGRAM, 0);
if (s < 0) {
perror("socket");
return -1;
}
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
ifr.ifr_flags = flags & 0xffff;
if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
perror("ioctl[SIOCSIFFLAGS]");
close(s);
return -1;
}
close(s);
return 0;
}
static int wpa_driver_wired_multi(const char *ifname, const u8 *addr, int add)
{
struct ifreq ifr;
int s;
s = socket(PF_INET, SOCK_DGRAM, 0);
if (s < 0) {
perror("socket");
return -1;
}
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
if (ioctl(s, add ? SIOCADDMULTI : SIOCDELMULTI, (caddr_t) &ifr) < 0) {
perror("ioctl[SIOC{ADD/DEL}MULTI]");
close(s);
return -1;
}
close(s);
return 0;
}
static int wpa_driver_wired_membership(struct wpa_driver_wired_data *drv,
const u8 *addr, int add)
{
#ifdef __linux__
struct packet_mreq mreq;
if (drv->pf_sock == -1)
return -1;
memset(&mreq, 0, sizeof(mreq));
mreq.mr_ifindex = if_nametoindex(drv->ifname);
mreq.mr_type = PACKET_MR_MULTICAST;
mreq.mr_alen = ETH_ALEN;
memcpy(mreq.mr_address, addr, ETH_ALEN);
if (setsockopt(drv->pf_sock, SOL_PACKET,
add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP,
&mreq, sizeof(mreq)) < 0) {
perror("setsockopt");
return -1;
}
return 0;
#else /* __linux__ */
return -1;
#endif /* __linux__ */
}
static void * wpa_driver_wired_init(void *ctx, const char *ifname)
{
struct wpa_driver_wired_data *drv;
int flags;
drv = malloc(sizeof(*drv));
if (drv == NULL)
return NULL;
memset(drv, 0, sizeof(*drv));
strncpy(drv->ifname, ifname, sizeof(drv->ifname));
drv->ctx = ctx;
#ifdef __linux__
drv->pf_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
if (drv->pf_sock < 0)
perror("socket(PF_PACKET)");
#else
drv->pf_sock = -1;
#endif
if (wpa_driver_wired_get_ifflags(ifname, &flags) == 0 &&
!(flags & IFF_UP) &&
wpa_driver_wired_set_ifflags(ifname, flags | IFF_UP) == 0) {
drv->iff_up = 1;
}
if (wpa_driver_wired_membership(drv, pae_group_addr, 1) == 0) {
wpa_printf(MSG_DEBUG, "%s: Added multicast membership with "
"packet socket", __func__);
drv->membership = 1;
} else if (wpa_driver_wired_multi(ifname, pae_group_addr, 1) == 0) {
wpa_printf(MSG_DEBUG, "%s: Added multicast membership with "
"SIOCADDMULTI", __func__);
drv->multi = 1;
} else if (wpa_driver_wired_get_ifflags(ifname, &flags) < 0) {
wpa_printf(MSG_INFO, "%s: Could not get interface "
"flags", __func__);
free(drv);
return NULL;
} else if (flags & IFF_ALLMULTI) {
wpa_printf(MSG_DEBUG, "%s: Interface is already configured "
"for multicast", __func__);
} else if (wpa_driver_wired_set_ifflags(ifname,
flags | IFF_ALLMULTI) < 0) {
wpa_printf(MSG_INFO, "%s: Failed to enable allmulti",
__func__);
free(drv);
return NULL;
} else {
wpa_printf(MSG_DEBUG, "%s: Enabled allmulti mode",
__func__);
drv->iff_allmulti = 1;
}
return drv;
}
static void wpa_driver_wired_deinit(void *priv)
{
struct wpa_driver_wired_data *drv = priv;
int flags;
if (drv->membership &&
wpa_driver_wired_membership(drv, pae_group_addr, 0) < 0) {
wpa_printf(MSG_DEBUG, "%s: Failed to remove PAE multicast "
"group (PACKET)", __func__);
}
if (drv->multi &&
wpa_driver_wired_multi(drv->ifname, pae_group_addr, 0) < 0) {
wpa_printf(MSG_DEBUG, "%s: Failed to remove PAE multicast "
"group (SIOCDELMULTI)", __func__);
}
if (drv->iff_allmulti &&
(wpa_driver_wired_get_ifflags(drv->ifname, &flags) < 0 ||
wpa_driver_wired_set_ifflags(drv->ifname,
flags & ~IFF_ALLMULTI) < 0)) {
wpa_printf(MSG_DEBUG, "%s: Failed to disable allmulti mode",
__func__);
}
if (drv->iff_up &&
wpa_driver_wired_get_ifflags(drv->ifname, &flags) == 0 &&
(flags & IFF_UP) &&
wpa_driver_wired_set_ifflags(drv->ifname, flags & ~IFF_UP) < 0) {
wpa_printf(MSG_DEBUG, "%s: Failed to set the interface down",
__func__);
}
if (drv->pf_sock != -1)
close(drv->pf_sock);
free(drv);
}
const struct wpa_driver_ops wpa_driver_wired_ops = {
.name = "wired",
.desc = "wpa_supplicant wired Ethernet driver",
.set_wpa = wpa_driver_wired_set_wpa,
.get_ssid = wpa_driver_wired_get_ssid,
.get_bssid = wpa_driver_wired_get_bssid,
.init = wpa_driver_wired_init,
.deinit = wpa_driver_wired_deinit,
};

View file

@ -1,6 +1,6 @@
/*
* WPA Supplicant / driver interface list
* Copyright (c) 2004, Jouni Malinen <jkmaline@cc.hut.fi>
* Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -49,6 +49,9 @@ extern struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */
#ifdef CONFIG_DRIVER_NDIS
extern struct wpa_driver_ops wpa_driver_ndis_ops; /* driver_ndis.c */
#endif /* CONFIG_DRIVER_NDIS */
#ifdef CONFIG_DRIVER_WIRED
extern struct wpa_driver_ops wpa_driver_wired_ops; /* driver_wired.c */
#endif /* CONFIG_DRIVER_WIRED */
#ifdef CONFIG_DRIVER_TEST
extern struct wpa_driver_ops wpa_driver_test_ops; /* driver_test.c */
#endif /* CONFIG_DRIVER_TEST */
@ -89,6 +92,9 @@ struct wpa_driver_ops *wpa_supplicant_drivers[] =
#ifdef CONFIG_DRIVER_NDIS
&wpa_driver_ndis_ops,
#endif /* CONFIG_DRIVER_NDIS */
#ifdef CONFIG_DRIVER_WIRED
&wpa_driver_wired_ops,
#endif /* CONFIG_DRIVER_WIRED */
#ifdef CONFIG_DRIVER_TEST
&wpa_driver_test_ops,
#endif /* CONFIG_DRIVER_TEST */

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,17 @@
/*
* WPA Supplicant / EAP state machine functions (RFC 4137)
* Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef EAP_H
#define EAP_H
@ -6,55 +20,237 @@
struct eap_sm;
struct wpa_ssid;
struct wpa_config_blob;
#ifdef IEEE8021X_EAPOL
/**
* enum eapol_bool_var - EAPOL boolean state variables for EAP state machine
*
* These variables are used in the interface between EAP peer state machine and
* lower layer. These are defined in RFC 4137, Sect. 4.1. Lower layer code is
* expected to maintain these variables and register a callback functions for
* EAP state machine to get and set the variables.
*/
enum eapol_bool_var {
EAPOL_eapSuccess, EAPOL_eapRestart, EAPOL_eapFail, EAPOL_eapResp,
EAPOL_eapNoResp, EAPOL_eapReq, EAPOL_portEnabled, EAPOL_altAccept,
/**
* EAPOL_eapSuccess - EAP SUCCESS state reached
*
* EAP state machine reads and writes this value.
*/
EAPOL_eapSuccess,
/**
* EAPOL_eapRestart - Lower layer request to restart authentication
*
* Set to TRUE in lower layer, FALSE in EAP state machine.
*/
EAPOL_eapRestart,
/**
* EAPOL_eapFail - EAP FAILURE state reached
*
* EAP state machine writes this value.
*/
EAPOL_eapFail,
/**
* EAPOL_eapResp - Response to send
*
* Set to TRUE in EAP state machine, FALSE in lower layer.
*/
EAPOL_eapResp,
/**
* EAPOL_eapNoResp - Request has been process; no response to send
*
* Set to TRUE in EAP state machine, FALSE in lower layer.
*/
EAPOL_eapNoResp,
/**
* EAPOL_eapReq - EAP request available from lower layer
*
* Set to TRUE in lower layer, FALSE in EAP state machine.
*/
EAPOL_eapReq,
/**
* EAPOL_portEnabled - Lower layer is ready for communication
*
* EAP state machines reads this value.
*/
EAPOL_portEnabled,
/**
* EAPOL_altAccept - Alternate indication of success (RFC3748)
*
* EAP state machines reads this value.
*/
EAPOL_altAccept,
/**
* EAPOL_altReject - Alternate indication of failure (RFC3748)
*
* EAP state machines reads this value.
*/
EAPOL_altReject
};
/**
* enum eapol_int_var - EAPOL integer state variables for EAP state machine
*
* These variables are used in the interface between EAP peer state machine and
* lower layer. These are defined in RFC 4137, Sect. 4.1. Lower layer code is
* expected to maintain these variables and register a callback functions for
* EAP state machine to get and set the variables.
*/
enum eapol_int_var {
/**
* EAPOL_idleWhile - Outside time for EAP peer timeout
*
* This integer variable is used to provide an outside timer that the
* external (to EAP state machine) code must decrement by one every
* second until the value reaches zero. This is used in the same way as
* EAPOL state machine timers. EAP state machine reads and writes this
* value.
*/
EAPOL_idleWhile
};
/**
* struct eapol_callbacks - Callback functions from EAP to lower layer
*
* This structure defines the callback functions that EAP state machine
* requires from the lower layer (usually EAPOL state machine) for updating
* state variables and requesting information. eapol_ctx from eap_sm_init()
* call will be used as the ctx parameter for these callback functions.
*/
struct eapol_callbacks {
/**
* get_config - Get pointer to the current network configuration
* @ctx: eapol_ctx from eap_sm_init() call
*/
struct wpa_ssid * (*get_config)(void *ctx);
/**
* get_bool - Get a boolean EAPOL state variable
* @variable: EAPOL boolean variable to get
* Returns: Value of the EAPOL variable
*/
Boolean (*get_bool)(void *ctx, enum eapol_bool_var variable);
/**
* set_bool - Set a boolean EAPOL state variable
* @ctx: eapol_ctx from eap_sm_init() call
* @variable: EAPOL boolean variable to set
* @value: Value for the EAPOL variable
*/
void (*set_bool)(void *ctx, enum eapol_bool_var variable,
Boolean value);
/**
* get_int - Get an integer EAPOL state variable
* @ctx: eapol_ctx from eap_sm_init() call
* @variable: EAPOL integer variable to get
* Returns: Value of the EAPOL variable
*/
unsigned int (*get_int)(void *ctx, enum eapol_int_var variable);
/**
* set_int - Set an integer EAPOL state variable
* @ctx: eapol_ctx from eap_sm_init() call
* @variable: EAPOL integer variable to set
* @value: Value for the EAPOL variable
*/
void (*set_int)(void *ctx, enum eapol_int_var variable,
unsigned int value);
/**
* get_eapReqData - Get EAP-Request data
* @ctx: eapol_ctx from eap_sm_init() call
* @len: Pointer to variable that will be set to eapReqDataLen
* Returns: Reference to eapReqData (EAP state machine will not free
* this) or %NULL if eapReqData not available.
*/
u8 * (*get_eapReqData)(void *ctx, size_t *len);
/**
* set_config_blob - Set named configuration blob
* @ctx: eapol_ctx from eap_sm_init() call
* @blob: New value for the blob
*
* Adds a new configuration blob or replaces the current value of an
* existing blob.
*/
void (*set_config_blob)(void *ctx, struct wpa_config_blob *blob);
/**
* get_config_blob - Get a named configuration blob
* @ctx: eapol_ctx from eap_sm_init() call
* @name: Name of the blob
* Returns: Pointer to blob data or %NULL if not found
*/
const struct wpa_config_blob * (*get_config_blob)(void *ctx,
const char *name);
};
struct eap_sm *eap_sm_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
void *msg_ctx);
/**
* struct eap_config - Configuration for EAP state machine
*/
struct eap_config {
/**
* opensc_engine_path - OpenSC engine for OpenSSL engine support
*
* Usually, path to engine_opensc.so.
*/
const char *opensc_engine_path;
/**
* pkcs11_engine_path - PKCS#11 engine for OpenSSL engine support
*
* Usually, path to engine_pkcs11.so.
*/
const char *pkcs11_engine_path;
/**
* pkcs11_module_path - OpenSC PKCS#11 module for OpenSSL engine
*
* Usually, path to opensc-pkcs11.so.
*/
const char *pkcs11_module_path;
};
struct eap_sm * eap_sm_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
void *msg_ctx, struct eap_config *conf);
void eap_sm_deinit(struct eap_sm *sm);
int eap_sm_step(struct eap_sm *sm);
void eap_sm_abort(struct eap_sm *sm);
int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen,
int verbose);
u8 *eap_sm_buildIdentity(struct eap_sm *sm, int id, size_t *len,
int encrypted);
u8 * eap_sm_buildIdentity(struct eap_sm *sm, int id, size_t *len,
int encrypted);
const struct eap_method * eap_sm_get_eap_methods(int method);
void eap_sm_request_identity(struct eap_sm *sm, struct wpa_ssid *config);
void eap_sm_request_password(struct eap_sm *sm, struct wpa_ssid *config);
void eap_sm_request_new_password(struct eap_sm *sm, struct wpa_ssid *config);
void eap_sm_request_pin(struct eap_sm *sm, struct wpa_ssid *config);
void eap_sm_request_otp(struct eap_sm *sm, struct wpa_ssid *config,
char *msg, size_t msg_len);
const char *msg, size_t msg_len);
void eap_sm_request_passphrase(struct eap_sm *sm, struct wpa_ssid *config);
void eap_sm_notify_ctrl_attached(struct eap_sm *sm);
u8 eap_get_type(const char *name);
const char * eap_get_name(EapType type);
size_t eap_get_names(char *buf, size_t buflen);
u8 eap_get_phase2_type(const char *name);
u8 *eap_get_phase2_types(struct wpa_ssid *config, size_t *count);
void eap_set_fast_reauth(struct eap_sm *sm, int enabled);
void eap_set_workaround(struct eap_sm *sm, unsigned int workaround);
void eap_set_force_disabled(struct eap_sm *sm, int disabled);
struct wpa_ssid * eap_get_config(struct eap_sm *sm);
int eap_key_available(struct eap_sm *sm);
void eap_notify_success(struct eap_sm *sm);
u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len);
void eap_notify_lower_layer_success(struct eap_sm *sm);
const u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len);
u8 * eap_get_eapRespData(struct eap_sm *sm, size_t *len);
void eap_register_scard_ctx(struct eap_sm *sm, void *ctx);
@ -65,6 +261,16 @@ static inline u8 eap_get_type(const char *name)
return EAP_TYPE_NONE;
}
static inline const char * eap_get_name(EapType type)
{
return NULL;
}
static inline size_t eap_get_names(char *buf, size_t buflen)
{
return 0;
}
#endif /* IEEE8021X_EAPOL */
#endif /* EAP_H */

View file

@ -20,7 +20,7 @@
#include "eap_i.h"
#include "wpa_supplicant.h"
#include "config_ssid.h"
#include "sha1.h"
#include "crypto.h"
#include "pcsc_funcs.h"
#include "eap_sim_common.h"
@ -211,7 +211,7 @@ static int eap_aka_learn_ids(struct eap_aka_data *data,
static u8 * eap_aka_client_error(struct eap_sm *sm, struct eap_aka_data *data,
struct eap_hdr *req,
const struct eap_hdr *req,
size_t *respDataLen, int err)
{
struct eap_sim_msg *msg;
@ -229,7 +229,7 @@ static u8 * eap_aka_client_error(struct eap_sm *sm, struct eap_aka_data *data,
static u8 * eap_aka_authentication_reject(struct eap_sm *sm,
struct eap_aka_data *data,
struct eap_hdr *req,
const struct eap_hdr *req,
size_t *respDataLen)
{
struct eap_sim_msg *msg;
@ -249,7 +249,7 @@ static u8 * eap_aka_authentication_reject(struct eap_sm *sm,
static u8 * eap_aka_synchronization_failure(struct eap_sm *sm,
struct eap_aka_data *data,
struct eap_hdr *req,
const struct eap_hdr *req,
size_t *respDataLen)
{
struct eap_sim_msg *msg;
@ -271,7 +271,7 @@ static u8 * eap_aka_synchronization_failure(struct eap_sm *sm,
static u8 * eap_aka_response_identity(struct eap_sm *sm,
struct eap_aka_data *data,
struct eap_hdr *req,
const struct eap_hdr *req,
size_t *respDataLen,
enum eap_sim_id_req id_req)
{
@ -300,7 +300,7 @@ static u8 * eap_aka_response_identity(struct eap_sm *sm,
eap_aka_clear_identities(data, CLEAR_EAP_ID);
wpa_printf(MSG_DEBUG, "Generating EAP-AKA Identity (id=%d)",
req->identifier);
req->identifier);
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, req->identifier,
EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY);
@ -317,13 +317,13 @@ static u8 * eap_aka_response_identity(struct eap_sm *sm,
static u8 * eap_aka_response_challenge(struct eap_sm *sm,
struct eap_aka_data *data,
struct eap_hdr *req,
const struct eap_hdr *req,
size_t *respDataLen)
{
struct eap_sim_msg *msg;
wpa_printf(MSG_DEBUG, "Generating EAP-AKA Challenge (id=%d)",
req->identifier);
req->identifier);
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, req->identifier,
EAP_TYPE_AKA, EAP_AKA_SUBTYPE_CHALLENGE);
wpa_printf(MSG_DEBUG, " AT_RES");
@ -337,7 +337,7 @@ static u8 * eap_aka_response_challenge(struct eap_sm *sm,
static u8 * eap_aka_response_reauth(struct eap_sm *sm,
struct eap_aka_data *data,
struct eap_hdr *req,
const struct eap_hdr *req,
size_t *respDataLen, int counter_too_small)
{
struct eap_sim_msg *msg;
@ -377,7 +377,7 @@ static u8 * eap_aka_response_reauth(struct eap_sm *sm,
static u8 * eap_aka_response_notification(struct eap_sm *sm,
struct eap_aka_data *data,
struct eap_hdr *req,
const struct eap_hdr *req,
size_t *respDataLen,
u16 notification)
{
@ -416,7 +416,8 @@ static u8 * eap_aka_response_notification(struct eap_sm *sm,
static u8 * eap_aka_process_identity(struct eap_sm *sm,
struct eap_aka_data *data,
struct eap_hdr *req, size_t reqDataLen,
const struct eap_hdr *req,
size_t reqDataLen,
size_t *respDataLen,
struct eap_sim_attrs *attr)
{
@ -458,7 +459,8 @@ static u8 * eap_aka_process_identity(struct eap_sm *sm,
static u8 * eap_aka_process_challenge(struct eap_sm *sm,
struct eap_aka_data *data,
struct eap_hdr *req, size_t reqDataLen,
const struct eap_hdr *req,
size_t reqDataLen,
size_t *respDataLen,
struct eap_sim_attrs *attr)
{
@ -512,8 +514,8 @@ static u8 * eap_aka_process_challenge(struct eap_sm *sm,
"derivation", identity, identity_len);
eap_aka_derive_mk(data, identity, identity_len);
eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk);
if (eap_sim_verify_mac(data->k_aut, (u8 *) req, reqDataLen, attr->mac,
(u8 *) "", 0)) {
if (eap_sim_verify_mac(data->k_aut, (const u8 *) req, reqDataLen,
attr->mac, (u8 *) "", 0)) {
wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
"used invalid AT_MAC");
return eap_aka_client_error(sm, data, req, respDataLen,
@ -527,14 +529,17 @@ static u8 * eap_aka_process_challenge(struct eap_sm *sm,
CLEAR_EAP_ID);
if (attr->encr_data) {
if (eap_sim_parse_encr(data->k_encr, attr->encr_data,
attr->encr_data_len, attr->iv, &eattr,
0)) {
u8 *decrypted;
decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
attr->encr_data_len, attr->iv,
&eattr, 0);
if (decrypted == NULL) {
return eap_aka_client_error(
sm, data, req, respDataLen,
EAP_AKA_UNABLE_TO_PROCESS_PACKET);
}
eap_aka_learn_ids(data, &eattr);
free(decrypted);
}
if (data->state != FAILURE)
@ -551,11 +556,12 @@ static u8 * eap_aka_process_challenge(struct eap_sm *sm,
static int eap_aka_process_notification_reauth(struct eap_aka_data *data,
struct eap_hdr *req,
const struct eap_hdr *req,
size_t reqDataLen,
struct eap_sim_attrs *attr)
{
struct eap_sim_attrs eattr;
u8 *decrypted;
if (attr->encr_data == NULL || attr->iv == NULL) {
wpa_printf(MSG_WARNING, "EAP-AKA: Notification message after "
@ -563,8 +569,10 @@ static int eap_aka_process_notification_reauth(struct eap_aka_data *data,
return -1;
}
if (eap_sim_parse_encr(data->k_encr, attr->encr_data,
attr->encr_data_len, attr->iv, &eattr, 0)) {
decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
attr->encr_data_len, attr->iv, &eattr,
0);
if (decrypted == NULL) {
wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted "
"data from notification message");
return -1;
@ -574,15 +582,17 @@ static int eap_aka_process_notification_reauth(struct eap_aka_data *data,
wpa_printf(MSG_WARNING, "EAP-AKA: Counter in notification "
"message does not match with counter in reauth "
"message");
free(decrypted);
return -1;
}
free(decrypted);
return 0;
}
static int eap_aka_process_notification_auth(struct eap_aka_data *data,
struct eap_hdr *req,
const struct eap_hdr *req,
size_t reqDataLen,
struct eap_sim_attrs *attr)
{
@ -592,8 +602,8 @@ static int eap_aka_process_notification_auth(struct eap_aka_data *data,
return -1;
}
if (eap_sim_verify_mac(data->k_aut, (u8 *) req, reqDataLen, attr->mac,
(u8 *) "", 0)) {
if (eap_sim_verify_mac(data->k_aut, (const u8 *) req, reqDataLen,
attr->mac, (u8 *) "", 0)) {
wpa_printf(MSG_WARNING, "EAP-AKA: Notification message "
"used invalid AT_MAC");
return -1;
@ -612,7 +622,7 @@ static int eap_aka_process_notification_auth(struct eap_aka_data *data,
static u8 * eap_aka_process_notification(struct eap_sm *sm,
struct eap_aka_data *data,
struct eap_hdr *req,
const struct eap_hdr *req,
size_t reqDataLen,
size_t *respDataLen,
struct eap_sim_attrs *attr)
@ -649,12 +659,13 @@ static u8 * eap_aka_process_notification(struct eap_sm *sm,
static u8 * eap_aka_process_reauthentication(struct eap_sm *sm,
struct eap_aka_data *data,
struct eap_hdr *req,
const struct eap_hdr *req,
size_t reqDataLen,
size_t *respDataLen,
struct eap_sim_attrs *attr)
{
struct eap_sim_attrs eattr;
u8 *decrypted;
wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Reauthentication");
@ -666,7 +677,7 @@ static u8 * eap_aka_process_reauthentication(struct eap_sm *sm,
}
data->reauth = 1;
if (eap_sim_verify_mac(data->k_aut, (u8 *) req, reqDataLen,
if (eap_sim_verify_mac(data->k_aut, (const u8 *) req, reqDataLen,
attr->mac, (u8 *) "", 0)) {
wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
"did not have valid AT_MAC");
@ -681,8 +692,10 @@ static u8 * eap_aka_process_reauthentication(struct eap_sm *sm,
EAP_AKA_UNABLE_TO_PROCESS_PACKET);
}
if (eap_sim_parse_encr(data->k_encr, attr->encr_data,
attr->encr_data_len, attr->iv, &eattr, 0)) {
decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
attr->encr_data_len, attr->iv, &eattr,
0);
if (decrypted == NULL) {
wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted "
"data from reauthentication message");
return eap_aka_client_error(sm, data, req, respDataLen,
@ -693,6 +706,7 @@ static u8 * eap_aka_process_reauthentication(struct eap_sm *sm,
wpa_printf(MSG_INFO, "EAP-AKA: (encr) No%s%s in reauth packet",
!eattr.nonce_s ? " AT_NONCE_S" : "",
eattr.counter < 0 ? " AT_COUNTER" : "");
free(decrypted);
return eap_aka_client_error(sm, data, req, respDataLen,
EAP_AKA_UNABLE_TO_PROCESS_PACKET);
}
@ -711,6 +725,7 @@ static u8 * eap_aka_process_reauthentication(struct eap_sm *sm,
data->last_eap_identity_len = data->reauth_id_len;
data->reauth_id = NULL;
data->reauth_id_len = 0;
free(decrypted);
return eap_aka_response_reauth(sm, data, req, respDataLen, 1);
}
data->counter = eattr.counter;
@ -735,19 +750,21 @@ static u8 * eap_aka_process_reauthentication(struct eap_sm *sm,
"fast reauths performed - force fullauth");
eap_aka_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
}
free(decrypted);
return eap_aka_response_reauth(sm, data, req, respDataLen, 0);
}
static u8 * eap_aka_process(struct eap_sm *sm, void *priv,
struct eap_method_ret *ret,
u8 *reqData, size_t reqDataLen,
const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
struct eap_aka_data *data = priv;
struct wpa_ssid *config = eap_get_config(sm);
struct eap_hdr *req;
u8 *pos, subtype, *res;
const struct eap_hdr *req;
u8 subtype, *res;
const u8 *pos;
struct eap_sim_attrs attr;
size_t len;
@ -759,21 +776,19 @@ static u8 * eap_aka_process(struct eap_sm *sm, void *priv,
return NULL;
}
req = (struct eap_hdr *) reqData;
pos = (u8 *) (req + 1);
if (reqDataLen < sizeof(*req) + 4 || *pos != EAP_TYPE_AKA ||
(len = be_to_host16(req->length)) > reqDataLen) {
wpa_printf(MSG_INFO, "EAP-AKA: Invalid frame");
pos = eap_hdr_validate(EAP_TYPE_AKA, reqData, reqDataLen, &len);
if (pos == NULL || len < 1) {
ret->ignore = TRUE;
return NULL;
}
req = (const struct eap_hdr *) reqData;
len = be_to_host16(req->length);
ret->ignore = FALSE;
ret->methodState = METHOD_CONT;
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
ret->allowNotifications = TRUE;
pos++;
subtype = *pos++;
wpa_printf(MSG_DEBUG, "EAP-AKA: Subtype=%d", subtype);
pos += 2; /* Reserved */
@ -818,7 +833,7 @@ done:
ret->decision = DECISION_FAIL;
ret->methodState = METHOD_DONE;
} else if (data->state == SUCCESS) {
ret->decision = DECISION_UNCOND_SUCC;
ret->decision = DECISION_COND_SUCC;
ret->methodState = METHOD_DONE;
}

View file

@ -1,3 +1,17 @@
/*
* WPA Supplicant/hostapd / Shared EAP definitions
* Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef EAP_DEFS_H
#define EAP_DEFS_H
@ -6,7 +20,7 @@
struct eap_hdr {
u8 code;
u8 identifier;
u16 length; /* including code and identifier */
u16 length; /* including code and identifier; network byte order */
/* followed by length-4 octets of data */
} __attribute__ ((packed));
@ -18,12 +32,12 @@ enum { EAP_CODE_REQUEST = 1, EAP_CODE_RESPONSE = 2, EAP_CODE_SUCCESS = 3,
typedef enum {
EAP_TYPE_NONE = 0,
EAP_TYPE_IDENTITY = 1,
EAP_TYPE_NOTIFICATION = 2,
EAP_TYPE_NAK = 3 /* Response only */,
EAP_TYPE_MD5 = 4,
EAP_TYPE_OTP = 5 /* RFC 2284 */,
EAP_TYPE_GTC = 6, /* RFC 2284 */
EAP_TYPE_IDENTITY = 1 /* RFC 3748 */,
EAP_TYPE_NOTIFICATION = 2 /* RFC 3748 */,
EAP_TYPE_NAK = 3 /* Response only, RFC 3748 */,
EAP_TYPE_MD5 = 4, /* RFC 3748 */
EAP_TYPE_OTP = 5 /* RFC 3748 */,
EAP_TYPE_GTC = 6, /* RFC 3748 */
EAP_TYPE_TLS = 13 /* RFC 2716 */,
EAP_TYPE_LEAP = 17 /* Cisco proprietary */,
EAP_TYPE_SIM = 18 /* draft-haverinen-pppext-eap-sim-12.txt */,
@ -33,9 +47,10 @@ typedef enum {
EAP_TYPE_MSCHAPV2 = 26 /* draft-kamath-pppext-eap-mschapv2-00.txt */,
EAP_TYPE_TLV = 33 /* draft-josefsson-pppext-eap-tls-eap-07.txt */,
EAP_TYPE_FAST = 43 /* draft-cam-winget-eap-fast-00.txt */,
EAP_TYPE_PAX = 46, /* draft-clancy-eap-pax-04.txt */
EAP_TYPE_EXPANDED_NAK = 254 /* RFC 3748 */,
EAP_TYPE_PSK = 255 /* EXPERIMENTAL - type not yet allocated
* draft-bersani-eap-psk-03 */
* draft-bersani-eap-psk-09 */
} EapType;
#endif /* EAP_DEFS_H */

View file

@ -24,10 +24,12 @@
#include "tls.h"
#include "eap_tlv.h"
#include "sha1.h"
#include "config.h"
/* TODO:
* - encrypt PAC-Key in the PAC file
* - test session resumption and enable it if it interoperates
* - password change (pending mschapv2 packet; replay decrypted packet)
*/
#define EAP_FAST_VERSION 1
@ -36,7 +38,8 @@
#define TLS_EXT_PAC_OPAQUE 35
static char *pac_file_hdr = "wpa_supplicant EAP-FAST PAC file - version 1";
static const char *pac_file_hdr =
"wpa_supplicant EAP-FAST PAC file - version 1";
static void eap_fast_deinit(struct eap_sm *sm, void *priv);
@ -58,28 +61,18 @@ struct pac_tlv_hdr {
};
/* draft-cam-winget-eap-fast-00.txt, 6.2 EAP-FAST Authentication Phase 1 */
/* draft-cam-winget-eap-fast-02.txt:
* 6.2 EAP-FAST Authentication Phase 1: Key Derivations */
struct eap_fast_key_block_auth {
/* RC4-128-SHA */
u8 client_write_MAC_secret[20];
u8 server_write_MAC_secret[20];
u8 client_write_key[16];
u8 server_write_key[16];
/* u8 client_write_IV[0]; */
/* u8 server_write_IV[0]; */
/* Extra key material after TLS key_block */
u8 session_key_seed[40];
};
/* draft-cam-winget-eap-fast-00.txt, 7.3 EAP-FAST Provisioning Exchange */
/* draft-cam-winget-eap-fast-provisioning-01.txt:
* 3.4 Key Derivations Used in the EAP-FAST Provisioning Exchange */
struct eap_fast_key_block_provisioning {
/* AES128-SHA */
u8 client_write_MAC_secret[20];
u8 server_write_MAC_secret[20];
u8 client_write_key[16];
u8 server_write_key[16];
u8 client_write_IV[16];
u8 server_write_IV[16];
/* Extra key material after TLS key_block */
u8 session_key_seed[40];
u8 server_challenge[16];
u8 client_challenge[16];
@ -249,12 +242,34 @@ static int eap_fast_add_pac(struct eap_fast_data *data,
}
static int eap_fast_read_line(FILE *f, char *buf, size_t buf_len)
struct eap_fast_read_ctx {
FILE *f;
const char *pos;
const char *end;
};
static int eap_fast_read_line(struct eap_fast_read_ctx *rc, char *buf,
size_t buf_len)
{
char *pos;
if (fgets(buf, buf_len, f) == NULL) {
return -1;
if (rc->f) {
if (fgets(buf, buf_len, rc->f) == NULL)
return -1;
} else {
const char *l_end;
size_t len;
if (rc->pos >= rc->end)
return -1;
l_end = rc->pos;
while (l_end < rc->end && *l_end != '\n')
l_end++;
len = l_end - rc->pos;
if (len >= buf_len)
len = buf_len - 1;
memcpy(buf, rc->pos, len);
buf[len] = '\0';
rc->pos = l_end + 1;
}
buf[buf_len - 1] = '\0';
@ -293,9 +308,10 @@ static u8 * eap_fast_parse_hex(const char *value, size_t *len)
}
static int eap_fast_load_pac(struct eap_fast_data *data, const char *pac_file)
static int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_data *data,
const char *pac_file)
{
FILE *f;
struct eap_fast_read_ctx rc;
struct eap_fast_pac *pac = NULL;
int count = 0;
char *buf, *pos;
@ -305,11 +321,27 @@ static int eap_fast_load_pac(struct eap_fast_data *data, const char *pac_file)
if (pac_file == NULL)
return -1;
f = fopen(pac_file, "r");
if (f == NULL) {
wpa_printf(MSG_INFO, "EAP-FAST: No PAC file '%s' - assume no "
"PAC entries have been provisioned", pac_file);
return 0;
memset(&rc, 0, sizeof(rc));
if (strncmp(pac_file, "blob://", 7) == 0) {
const struct wpa_config_blob *blob;
blob = eap_get_config_blob(sm, pac_file + 7);
if (blob == NULL) {
wpa_printf(MSG_INFO, "EAP-FAST: No PAC blob '%s' - "
"assume no PAC entries have been "
"provisioned", pac_file + 7);
return 0;
}
rc.pos = (char *) blob->data;
rc.end = (char *) blob->data + blob->len;
} else {
rc.f = fopen(pac_file, "r");
if (rc.f == NULL) {
wpa_printf(MSG_INFO, "EAP-FAST: No PAC file '%s' - "
"assume no PAC entries have been "
"provisioned", pac_file);
return 0;
}
}
buf = malloc(buf_len);
@ -318,16 +350,17 @@ static int eap_fast_load_pac(struct eap_fast_data *data, const char *pac_file)
}
line++;
if (eap_fast_read_line(f, buf, buf_len) < 0 ||
if (eap_fast_read_line(&rc, buf, buf_len) < 0 ||
strcmp(pac_file_hdr, buf) != 0) {
wpa_printf(MSG_INFO, "EAP-FAST: Unrecognized header line in "
"PAC file '%s'", pac_file);
free(buf);
fclose(f);
if (rc.f)
fclose(rc.f);
return -1;
}
while (eap_fast_read_line(f, buf, buf_len) == 0) {
while (eap_fast_read_line(&rc, buf, buf_len) == 0) {
line++;
pos = strchr(buf, '=');
if (pos) {
@ -423,7 +456,8 @@ static int eap_fast_load_pac(struct eap_fast_data *data, const char *pac_file)
}
free(buf);
fclose(f);
if (rc.f)
fclose(rc.f);
if (ret == 0) {
wpa_printf(MSG_DEBUG, "EAP-FAST: read %d PAC entries from "
@ -434,67 +468,124 @@ static int eap_fast_load_pac(struct eap_fast_data *data, const char *pac_file)
}
static void eap_fast_write(FILE *f, const char *field, const u8 *data,
static void eap_fast_write(char **buf, char **pos, size_t *buf_len,
const char *field, const u8 *data,
size_t len, int txt)
{
int i;
size_t need;
if (data == NULL)
if (data == NULL || *buf == NULL)
return;
fprintf(f, "%s=", field);
for (i = 0; i < len; i++) {
fprintf(f, "%02x", data[i]);
need = strlen(field) + len * 2 + 30;
if (txt)
need += strlen(field) + len + 20;
if (*pos - *buf + need > *buf_len) {
char *nbuf = realloc(*buf, *buf_len + need);
if (nbuf == NULL) {
free(*buf);
*buf = NULL;
return;
}
*buf = nbuf;
*buf_len += need;
}
fprintf(f, "\n");
*pos += snprintf(*pos, *buf + *buf_len - *pos, "%s=", field);
for (i = 0; i < len; i++) {
*pos += snprintf(*pos, *buf + *buf_len - *pos,
"%02x", data[i]);
}
*pos += snprintf(*pos, *buf + *buf_len - *pos, "\n");
if (txt) {
fprintf(f, "%s-txt=", field);
*pos += snprintf(*pos, *buf + *buf_len - *pos,
"%s-txt=", field);
for (i = 0; i < len; i++) {
fprintf(f, "%c", data[i]);
*pos += snprintf(*pos, *buf + *buf_len - *pos,
"%c", data[i]);
}
fprintf(f, "\n");
*pos += snprintf(*pos, *buf + *buf_len - *pos, "\n");
}
}
static int eap_fast_save_pac(struct eap_fast_data *data, const char *pac_file)
static int eap_fast_save_pac(struct eap_sm *sm, struct eap_fast_data *data,
const char *pac_file)
{
FILE *f;
struct eap_fast_pac *pac;
int count = 0;
char *buf, *pos;
size_t buf_len;
if (pac_file == NULL)
return -1;
f = fopen(pac_file, "w");
if (f == NULL) {
wpa_printf(MSG_INFO, "EAP-FAST: Failed to open PAC file '%s' "
"for writing", pac_file);
buf_len = 1024;
pos = buf = malloc(buf_len);
if (buf == NULL)
return -1;
}
fprintf(f, "%s\n", pac_file_hdr);
pos += snprintf(pos, buf + buf_len - pos, "%s\n", pac_file_hdr);
pac = data->pac;
while (pac) {
fprintf(f, "START\n");
eap_fast_write(f, "PAC-Key", pac->pac_key,
pos += snprintf(pos, buf + buf_len - pos, "START\n");
eap_fast_write(&buf, &pos, &buf_len, "PAC-Key", pac->pac_key,
EAP_FAST_PAC_KEY_LEN, 0);
eap_fast_write(f, "PAC-Opaque", pac->pac_opaque,
pac->pac_opaque_len, 0);
eap_fast_write(f, "PAC-Info", pac->pac_info,
eap_fast_write(&buf, &pos, &buf_len, "PAC-Opaque",
pac->pac_opaque, pac->pac_opaque_len, 0);
eap_fast_write(&buf, &pos, &buf_len, "PAC-Info", pac->pac_info,
pac->pac_info_len, 0);
eap_fast_write(f, "A-ID", pac->a_id, pac->a_id_len, 0);
eap_fast_write(f, "I-ID", pac->i_id, pac->i_id_len, 1);
eap_fast_write(f, "A-ID-Info", pac->a_id_info,
pac->a_id_info_len, 1);
fprintf(f, "END\n");
eap_fast_write(&buf, &pos, &buf_len, "A-ID", pac->a_id,
pac->a_id_len, 0);
eap_fast_write(&buf, &pos, &buf_len, "I-ID", pac->i_id,
pac->i_id_len, 1);
eap_fast_write(&buf, &pos, &buf_len, "A-ID-Info",
pac->a_id_info, pac->a_id_info_len, 1);
pos += snprintf(pos, buf + buf_len - pos, "END\n");
count++;
pac = pac->next;
if (buf == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: No memory for PAC "
"data");
return -1;
}
}
fclose(f);
if (strncmp(pac_file, "blob://", 7) == 0) {
struct wpa_config_blob *blob;
blob = malloc(sizeof(*blob));
if (blob == NULL) {
free(buf);
return -1;
}
memset(blob, 0, sizeof(*blob));
blob->data = (u8 *) buf;
blob->len = pos - buf;
buf = NULL;
blob->name = strdup(pac_file + 7);
if (blob->name == NULL) {
wpa_config_free_blob(blob);
return -1;
}
eap_set_config_blob(sm, blob);
} else {
f = fopen(pac_file, "w");
if (f == NULL) {
wpa_printf(MSG_INFO, "EAP-FAST: Failed to open PAC "
"file '%s' for writing", pac_file);
free(buf);
return -1;
}
fprintf(f, "%s", buf);
free(buf);
fclose(f);
}
wpa_printf(MSG_DEBUG, "EAP-FAST: wrote %d PAC entries into '%s'",
count, pac_file);
@ -590,7 +681,7 @@ static void * eap_fast_init(struct eap_sm *sm)
* TODO: consider making this configurable */
tls_connection_enable_workaround(sm->ssl_ctx, data->ssl.conn);
if (eap_fast_load_pac(data, config->pac_file) < 0) {
if (eap_fast_load_pac(sm, data, config->pac_file) < 0) {
eap_fast_deinit(sm, data);
return NULL;
}
@ -632,7 +723,7 @@ static void eap_fast_deinit(struct eap_sm *sm, void *priv)
static int eap_fast_encrypt(struct eap_sm *sm, struct eap_fast_data *data,
int id, u8 *plain, size_t plain_len,
int id, const u8 *plain, size_t plain_len,
u8 **out_data, size_t *out_len)
{
int res;
@ -799,32 +890,37 @@ static u8 * eap_fast_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
char *label, size_t len)
{
struct tls_keys keys;
u8 *random;
u8 *rnd;
u8 *out;
int block_size;
if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
return NULL;
out = malloc(len);
random = malloc(keys.client_random_len + keys.server_random_len);
if (out == NULL || random == NULL) {
block_size = tls_connection_get_keyblock_size(sm->ssl_ctx, data->conn);
if (block_size < 0)
return NULL;
out = malloc(block_size + len);
rnd = malloc(keys.client_random_len + keys.server_random_len);
if (out == NULL || rnd == NULL) {
free(out);
free(random);
free(rnd);
return NULL;
}
memcpy(random, keys.server_random, keys.server_random_len);
memcpy(random + keys.server_random_len, keys.client_random,
memcpy(rnd, keys.server_random, keys.server_random_len);
memcpy(rnd + keys.server_random_len, keys.client_random,
keys.client_random_len);
wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: master_secret for key "
"expansion", keys.master_key, keys.master_key_len);
if (tls_prf(keys.master_key, keys.master_key_len,
label, random, keys.client_random_len +
keys.server_random_len, out, len)) {
free(random);
label, rnd, keys.client_random_len +
keys.server_random_len, out, block_size + len)) {
free(rnd);
free(out);
return NULL;
}
free(random);
free(rnd);
memmove(out, out + block_size, len);
return out;
}
@ -836,6 +932,11 @@ static void eap_fast_derive_key_auth(struct eap_sm *sm,
data->key_block_a = (struct eap_fast_key_block_auth *)
eap_fast_derive_key(sm, &data->ssl, "key expansion",
sizeof(*data->key_block_a));
if (data->key_block_a == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive "
"session_key_seed");
return;
}
wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: session_key_seed",
data->key_block_a->session_key_seed,
sizeof(data->key_block_a->session_key_seed));
@ -878,7 +979,7 @@ static void eap_fast_derive_keys(struct eap_sm *sm, struct eap_fast_data *data)
static int eap_fast_phase2_request(struct eap_sm *sm,
struct eap_fast_data *data,
struct eap_method_ret *ret,
struct eap_hdr *req,
const struct eap_hdr *req,
struct eap_hdr *hdr,
u8 **resp, size_t *resp_len)
{
@ -1333,7 +1434,7 @@ static u8 * eap_fast_process_pac(struct eap_sm *sm, struct eap_fast_data *data,
}
eap_fast_add_pac(data, &entry);
eap_fast_save_pac(data, config->pac_file);
eap_fast_save_pac(sm, data, config->pac_file);
if (data->provisioning) {
/* EAP-FAST provisioning does not provide keying material and
@ -1356,12 +1457,13 @@ static u8 * eap_fast_process_pac(struct eap_sm *sm, struct eap_fast_data *data,
static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
struct eap_method_ret *ret, struct eap_hdr *req,
u8 *in_data, size_t in_len,
struct eap_method_ret *ret,
const struct eap_hdr *req,
const u8 *in_data, size_t in_len,
u8 **out_data, size_t *out_len)
{
u8 *in_decrypted, *pos, *end;
int buf_len, len_decrypted, len, res;
int buf_len, len_decrypted, len;
struct eap_hdr *hdr;
u8 *resp = NULL;
size_t resp_len;
@ -1371,13 +1473,17 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
int iresult = 0, result = 0;
struct eap_tlv_crypto_binding__tlv *crypto_binding = NULL;
size_t crypto_binding_len = 0;
const u8 *msg;
size_t msg_len;
int need_more_input;
wpa_printf(MSG_DEBUG, "EAP-FAST: received %lu bytes encrypted data for"
" Phase 2", (unsigned long) in_len);
res = eap_tls_data_reassemble(sm, &data->ssl, &in_data, &in_len);
if (res < 0 || res == 1)
return res;
msg = eap_tls_data_reassemble(sm, &data->ssl, in_data, in_len,
&msg_len, &need_more_input);
if (msg == NULL)
return need_more_input ? 1 : -1;
buf_len = in_len;
if (data->ssl.tls_in_total > buf_len)
@ -1393,7 +1499,7 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
}
len_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
in_data, in_len,
msg, msg_len,
in_decrypted, buf_len);
free(data->ssl.tls_in);
data->ssl.tls_in = NULL;
@ -1417,11 +1523,12 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
pos = in_decrypted;
end = in_decrypted + len_decrypted;
while (pos < end) {
while (pos + 4 < end) {
mandatory = pos[0] & 0x80;
tlv_type = ((pos[0] & 0x3f) << 8) | pos[1];
len = (pos[2] << 8) | pos[3];
pos += 4;
tlv_type = WPA_GET_BE16(pos) & 0x3fff;
pos += 2;
len = WPA_GET_BE16(pos);
pos += 2;
if (pos + len > end) {
free(in_decrypted);
wpa_printf(MSG_INFO, "EAP-FAST: TLV overflow");
@ -1447,7 +1554,7 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
result = EAP_TLV_RESULT_FAILURE;
break;
}
result = (pos[0] << 16) | pos[1];
result = WPA_GET_BE16(pos);
if (result != EAP_TLV_RESULT_SUCCESS &&
result != EAP_TLV_RESULT_FAILURE) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown "
@ -1467,7 +1574,7 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
iresult = EAP_TLV_RESULT_FAILURE;
break;
}
iresult = (pos[0] << 16) | pos[1];
iresult = WPA_GET_BE16(pos);
if (iresult != EAP_TLV_RESULT_SUCCESS &&
iresult != EAP_TLV_RESULT_FAILURE) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown "
@ -1584,7 +1691,7 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
if (!resp && pac && result != EAP_TLV_RESULT_SUCCESS) {
wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV without Result TLV "
"acnowledging success");
"acknowledging success");
resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0,
&resp_len);
if (!resp) {
@ -1607,7 +1714,7 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
if (resp == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: No recognized TLVs - send "
"empty response packet");
resp = malloc(0);
resp = malloc(1);
if (resp == NULL)
return 0;
resp_len = 0;
@ -1628,65 +1735,25 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
static u8 * eap_fast_process(struct eap_sm *sm, void *priv,
struct eap_method_ret *ret,
u8 *reqData, size_t reqDataLen,
const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
struct eap_hdr *req;
int left, res;
unsigned int tls_msg_len;
u8 flags, *pos, *resp, id;
const struct eap_hdr *req;
size_t left;
int res;
u8 flags, *resp, id;
const u8 *pos;
struct eap_fast_data *data = priv;
if (tls_get_errors(sm->ssl_ctx)) {
wpa_printf(MSG_INFO, "EAP-FAST: TLS errors detected");
ret->ignore = TRUE;
pos = eap_tls_process_init(sm, &data->ssl, EAP_TYPE_FAST, ret,
reqData, reqDataLen, &left, &flags);
if (pos == NULL)
return NULL;
}
req = (struct eap_hdr *) reqData;
pos = (u8 *) (req + 1);
if (reqDataLen < sizeof(*req) + 2 || *pos != EAP_TYPE_FAST ||
(left = host_to_be16(req->length)) > reqDataLen) {
wpa_printf(MSG_INFO, "EAP-FAST: Invalid frame");
ret->ignore = TRUE;
return NULL;
}
left -= sizeof(struct eap_hdr);
req = (const struct eap_hdr *) reqData;
id = req->identifier;
pos++;
flags = *pos++;
left -= 2;
wpa_printf(MSG_DEBUG, "EAP-FAST: Received packet(len=%lu) - "
"Flags 0x%02x", (unsigned long) reqDataLen, flags);
if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
if (left < 4) {
wpa_printf(MSG_INFO, "EAP-FAST: Short frame with TLS "
"length");
ret->ignore = TRUE;
return NULL;
}
tls_msg_len = (pos[0] << 24) | (pos[1] << 16) | (pos[2] << 8) |
pos[3];
wpa_printf(MSG_DEBUG, "EAP-FAST: TLS Message Length: %d",
tls_msg_len);
if (data->ssl.tls_in_left == 0) {
data->ssl.tls_in_total = tls_msg_len;
data->ssl.tls_in_left = tls_msg_len;
free(data->ssl.tls_in);
data->ssl.tls_in = NULL;
data->ssl.tls_in_len = 0;
}
pos += 4;
left -= 4;
}
ret->ignore = FALSE;
ret->methodState = METHOD_CONT;
ret->decision = DECISION_FAIL;
ret->allowNotifications = TRUE;
if (flags & EAP_TLS_FLAGS_START) {
u8 *a_id;
const u8 *a_id;
size_t a_id_len;
struct pac_tlv_hdr *hdr;

View file

@ -53,29 +53,27 @@ static void eap_gtc_deinit(struct eap_sm *sm, void *priv)
static u8 * eap_gtc_process(struct eap_sm *sm, void *priv,
struct eap_method_ret *ret,
u8 *reqData, size_t reqDataLen,
const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
struct eap_gtc_data *data = priv;
struct wpa_ssid *config = eap_get_config(sm);
struct eap_hdr *req, *resp;
u8 *pos, *password;
size_t password_len, len, msg_len;
const struct eap_hdr *req;
struct eap_hdr *resp;
const u8 *pos, *password;
u8 *rpos;
size_t password_len, len;
req = (struct eap_hdr *) reqData;
pos = (u8 *) (req + 1);
if (reqDataLen < sizeof(*req) + 1 || *pos != EAP_TYPE_GTC ||
(len = be_to_host16(req->length)) > reqDataLen) {
wpa_printf(MSG_INFO, "EAP-GTC: Invalid frame");
pos = eap_hdr_validate(EAP_TYPE_GTC, reqData, reqDataLen, &len);
if (pos == NULL) {
ret->ignore = TRUE;
return NULL;
}
pos++;
msg_len = len - sizeof(*req) - 1;
wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Request message",
pos, msg_len);
req = (const struct eap_hdr *) reqData;
wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Request message", pos, len);
if (data->prefix &&
(msg_len < 10 || memcmp(pos, "CHALLENGE=", 10) != 0)) {
(len < 10 || memcmp(pos, "CHALLENGE=", 10) != 0)) {
wpa_printf(MSG_DEBUG, "EAP-GTC: Challenge did not start with "
"expected prefix");
@ -90,16 +88,15 @@ static u8 * eap_gtc_process(struct eap_sm *sm, void *priv,
resp->code = EAP_CODE_RESPONSE;
resp->identifier = req->identifier;
resp->length = host_to_be16(*respDataLen);
pos = (u8 *) (resp + 1);
*pos++ = EAP_TYPE_GTC;
rpos = (u8 *) (resp + 1);
*rpos++ = EAP_TYPE_GTC;
return (u8 *) resp;
}
if (config == NULL ||
(config->password == NULL && config->otp == NULL)) {
wpa_printf(MSG_INFO, "EAP-GTC: Password not configured");
eap_sm_request_otp(sm, config, (char *) pos,
len - sizeof(*req) - 1);
eap_sm_request_otp(sm, config, (const char *) pos, len);
ret->ignore = TRUE;
return NULL;
}
@ -128,16 +125,16 @@ static u8 * eap_gtc_process(struct eap_sm *sm, void *priv,
resp->code = EAP_CODE_RESPONSE;
resp->identifier = req->identifier;
resp->length = host_to_be16(*respDataLen);
pos = (u8 *) (resp + 1);
*pos++ = EAP_TYPE_GTC;
rpos = (u8 *) (resp + 1);
*rpos++ = EAP_TYPE_GTC;
if (data->prefix) {
memcpy(pos, "RESPONSE=", 9);
pos += 9;
memcpy(pos, config->identity, config->identity_len);
pos += config->identity_len;
*pos++ = '\0';
memcpy(rpos, "RESPONSE=", 9);
rpos += 9;
memcpy(rpos, config->identity, config->identity_len);
rpos += config->identity_len;
*rpos++ = '\0';
}
memcpy(pos, password, password_len);
memcpy(rpos, password, password_len);
wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-GTC: Response",
(u8 *) (resp + 1) + 1,
*respDataLen - sizeof(struct eap_hdr) - 1);

View file

@ -1,9 +1,23 @@
/*
* WPA Supplicant / EAP state machines internal structures (RFC 4137)
* Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef EAP_I_H
#define EAP_I_H
#include "eap.h"
/* draft-ietf-eap-statemachine-05.pdf - Peer state machine */
/* RFC 4137 - EAP Peer state machine */
typedef enum {
DECISION_FAIL, DECISION_COND_SUCC, DECISION_UNCOND_SUCC
@ -13,37 +27,190 @@ typedef enum {
METHOD_NONE, METHOD_INIT, METHOD_CONT, METHOD_MAY_CONT, METHOD_DONE
} EapMethodState;
/**
* struct eap_method_ret - EAP return values from struct eap_method::process()
*
* These structure contains OUT variables for the interface between peer state
* machine and methods (RFC 4137, Sect. 4.2). eapRespData will be returned as
* the return value of struct eap_method::process() so it is not included in
* this structure.
*/
struct eap_method_ret {
/**
* ignore - Whether method decided to drop the current packed (OUT)
*/
Boolean ignore;
/**
* methodState - Method-specific state (IN/OUT)
*/
EapMethodState methodState;
/**
* decision - Authentication decision (OUT)
*/
EapDecision decision;
/**
* allowNotifications - Whether method allows notifications (OUT)
*/
Boolean allowNotifications;
};
/**
* struct eap_method - EAP method interface
* This structure defines the EAP method interface. Each method will need to
* register its own EAP type, EAP name, and set of function pointers for method
* specific operations. This interface is based on section 4.4 of RFC 4137.
*/
struct eap_method {
/**
* method - EAP type number (EAP_TYPE_*)
*/
EapType method;
/**
* name - Name of the method (e.g., "TLS")
*/
const char *name;
/**
* init - Initialize an EAP method
* @sm: Pointer to EAP state machine allocated with eap_sm_init()
* Returns: Pointer to allocated private data, or %NULL on failure
*
* This function is used to initialize the EAP method explicitly
* instead of using METHOD_INIT state as specific in RFC 4137. The
* method is expected to initialize it method-specific state and return
* a pointer that will be used as the priv argument to other calls.
*/
void * (*init)(struct eap_sm *sm);
/**
* deinit - Deinitialize an EAP method
* @sm: Pointer to EAP state machine allocated with eap_sm_init()
* @priv: Pointer to private EAP method data from eap_method::init()
*
* Deinitialize the EAP method and free any allocated private data.
*/
void (*deinit)(struct eap_sm *sm, void *priv);
/**
* process - Process an EAP request
* @sm: Pointer to EAP state machine allocated with eap_sm_init()
* @priv: Pointer to private EAP method data from eap_method::init()
* @ret: Return values from EAP request validation and processing
* @reqData: EAP request to be processed (eapReqData)
* @reqDataLen: Length of the EAP request
* @respDataLen: Length of the returned EAP response
* Returns: Pointer to allocated EAP response packet (eapRespData)
*
* This function is a combination of m.check(), m.process(), and
* m.buildResp() procedures defined in section 4.4 of RFC 4137 In other
* words, this function validates the incoming request, processes it,
* and build a response packet. m.check() and m.process() return values
* are returned through struct eap_method_ret *ret variable. Caller is
* responsible for freeing the returned EAP response packet.
*/
u8 * (*process)(struct eap_sm *sm, void *priv,
struct eap_method_ret *ret,
u8 *reqData, size_t reqDataLen,
const u8 *reqData, size_t reqDataLen,
size_t *respDataLen);
/**
* isKeyAvailable - Find out whether EAP method has keying material
* @sm: Pointer to EAP state machine allocated with eap_sm_init()
* @priv: Pointer to private EAP method data from eap_method::init()
* Returns: %TRUE if key material (eapKeyData) is available
*/
Boolean (*isKeyAvailable)(struct eap_sm *sm, void *priv);
/**
* getKey - Get EAP method specific keying material (eapKeyData)
* @sm: Pointer to EAP state machine allocated with eap_sm_init()
* @priv: Pointer to private EAP method data from eap_method::init()
* @len: Pointer to variable to store key length (eapKeyDataLen)
* Returns: Keying material (eapKeyData) or %NULL if not available
*
* This function can be used to get the keying material from the EAP
* method. The key may already be stored in the method-specific private
* data or this function may derive the key.
*/
u8 * (*getKey)(struct eap_sm *sm, void *priv, size_t *len);
/**
* get_status - Get EAP method status
* @sm: Pointer to EAP state machine allocated with eap_sm_init()
* @priv: Pointer to private EAP method data from eap_method::init()
* @buf: Buffer for status information
* @buflen: Maximum buffer length
* @verbose: Whether to include verbose status information
* Returns: Number of bytes written to buf
*
* Query EAP method for status information. This function fills in a
* text area with current status information from the EAP method. If
* the buffer (buf) is not large enough, status information will be
* truncated to fit the buffer.
*/
int (*get_status)(struct eap_sm *sm, void *priv, char *buf,
size_t buflen, int verbose);
/* Optional handlers for fast re-authentication */
/**
* has_reauth_data - Whether method is ready for fast reauthentication
* @sm: Pointer to EAP state machine allocated with eap_sm_init()
* @priv: Pointer to private EAP method data from eap_method::init()
* Returns: %TRUE or %FALSE based on whether fast reauthentication is
* possible
*
* This function is an optional handler that only EAP methods
* supporting fast re-authentication need to implement.
*/
Boolean (*has_reauth_data)(struct eap_sm *sm, void *priv);
/**
* deinit_for_reauth - Release data that is not needed for fast re-auth
* @sm: Pointer to EAP state machine allocated with eap_sm_init()
* @priv: Pointer to private EAP method data from eap_method::init()
*
* This function is an optional handler that only EAP methods
* supporting fast re-authentication need to implement. This is called
* when authentication has been completed and EAP state machine is
* requesting that enough state information is maintained for fast
* re-authentication
*/
void (*deinit_for_reauth)(struct eap_sm *sm, void *priv);
/**
* init_for_reauth - Prepare for start of fast re-authentication
* @sm: Pointer to EAP state machine allocated with eap_sm_init()
* @priv: Pointer to private EAP method data from eap_method::init()
*
* This function is an optional handler that only EAP methods
* supporting fast re-authentication need to implement. This is called
* when EAP authentication is started and EAP state machine is
* requesting fast re-authentication to be used.
*/
void * (*init_for_reauth)(struct eap_sm *sm, void *priv);
/**
* get_identity - Get method specific identity for re-authentication
* @sm: Pointer to EAP state machine allocated with eap_sm_init()
* @priv: Pointer to private EAP method data from eap_method::init()
* @len: Length of the returned identity
* Returns: Pointer to the method specific identity or %NULL if default
* identity is to be used
*
* This function is an optional handler that only EAP methods
* that use method specific identity need to implement.
*/
const u8 * (*get_identity)(struct eap_sm *sm, void *priv, size_t *len);
};
/**
* struct eap_sm - EAP state machine data
*/
struct eap_sm {
enum {
EAP_INITIALIZE, EAP_DISABLED, EAP_IDLE, EAP_RECEIVED,
@ -76,7 +243,7 @@ struct eap_sm {
u8 *eapKeyData; /* peer to lower layer */
size_t eapKeyDataLen; /* peer to lower layer */
const struct eap_method *m; /* selected EAP method */
/* not defined in draft-ietf-eap-statemachine-02 */
/* not defined in RFC 4137 */
Boolean changed;
void *eapol_ctx;
struct eapol_callbacks *eapol_cb;
@ -101,6 +268,13 @@ struct eap_sm {
u8 *peer_challenge, *auth_challenge;
int num_rounds;
int force_disabled;
};
const u8 * eap_hdr_validate(EapType eap_type, const u8 *msg, size_t msglen,
size_t *plen);
void eap_set_config_blob(struct eap_sm *sm, struct wpa_config_blob *blob);
const struct wpa_config_blob *
eap_get_config_blob(struct eap_sm *sm, const char *name);
#endif /* EAP_I_H */

View file

@ -21,7 +21,7 @@
#include "wpa_supplicant.h"
#include "config_ssid.h"
#include "ms_funcs.h"
#include "md5.h"
#include "crypto.h"
#define LEAP_VERSION 1
#define LEAP_CHALLENGE_LEN 8
@ -68,18 +68,20 @@ static void eap_leap_deinit(struct eap_sm *sm, void *priv)
static u8 * eap_leap_process_request(struct eap_sm *sm, void *priv,
struct eap_method_ret *ret,
u8 *reqData, size_t reqDataLen,
const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
struct eap_leap_data *data = priv;
struct wpa_ssid *config = eap_get_config(sm);
struct eap_hdr *req, *resp;
u8 *pos, *challenge, challenge_len;
const struct eap_hdr *req;
struct eap_hdr *resp;
const u8 *pos, *challenge;
u8 challenge_len, *rpos;
wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Request");
req = (struct eap_hdr *) reqData;
pos = (u8 *) (req + 1);
req = (const struct eap_hdr *) reqData;
pos = (const u8 *) (req + 1);
if (reqDataLen < sizeof(*req) + 4 || *pos != EAP_TYPE_LEAP) {
wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Request frame");
ret->ignore = TRUE;
@ -121,17 +123,18 @@ static u8 * eap_leap_process_request(struct eap_sm *sm, void *priv,
resp->code = EAP_CODE_RESPONSE;
resp->identifier = req->identifier;
resp->length = host_to_be16(*respDataLen);
pos = (u8 *) (resp + 1);
*pos++ = EAP_TYPE_LEAP;
*pos++ = LEAP_VERSION;
*pos++ = 0; /* unused */
*pos++ = LEAP_RESPONSE_LEN;
rpos = (u8 *) (resp + 1);
*rpos++ = EAP_TYPE_LEAP;
*rpos++ = LEAP_VERSION;
*rpos++ = 0; /* unused */
*rpos++ = LEAP_RESPONSE_LEN;
nt_challenge_response(challenge,
config->password, config->password_len, pos);
memcpy(data->peer_response, pos, LEAP_RESPONSE_LEN);
wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Response", pos, LEAP_RESPONSE_LEN);
pos += LEAP_RESPONSE_LEN;
memcpy(pos, config->identity, config->identity_len);
config->password, config->password_len, rpos);
memcpy(data->peer_response, rpos, LEAP_RESPONSE_LEN);
wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Response",
rpos, LEAP_RESPONSE_LEN);
rpos += LEAP_RESPONSE_LEN;
memcpy(rpos, config->identity, config->identity_len);
data->state = LEAP_WAIT_SUCCESS;
@ -141,12 +144,13 @@ static u8 * eap_leap_process_request(struct eap_sm *sm, void *priv,
static u8 * eap_leap_process_success(struct eap_sm *sm, void *priv,
struct eap_method_ret *ret,
u8 *reqData, size_t reqDataLen,
const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
struct eap_leap_data *data = priv;
struct wpa_ssid *config = eap_get_config(sm);
struct eap_hdr *req, *resp;
const struct eap_hdr *req;
struct eap_hdr *resp;
u8 *pos;
wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Success");
@ -158,7 +162,7 @@ static u8 * eap_leap_process_success(struct eap_sm *sm, void *priv,
return NULL;
}
req = (struct eap_hdr *) reqData;
req = (const struct eap_hdr *) reqData;
*respDataLen = sizeof(struct eap_hdr) + 1 + 3 + LEAP_CHALLENGE_LEN +
config->identity_len;
@ -194,19 +198,20 @@ static u8 * eap_leap_process_success(struct eap_sm *sm, void *priv,
static u8 * eap_leap_process_response(struct eap_sm *sm, void *priv,
struct eap_method_ret *ret,
u8 *reqData, size_t reqDataLen,
const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
struct eap_leap_data *data = priv;
struct wpa_ssid *config = eap_get_config(sm);
struct eap_hdr *resp;
u8 *pos, response_len, pw_hash[16], pw_hash_hash[16],
const struct eap_hdr *resp;
const u8 *pos;
u8 response_len, pw_hash[16], pw_hash_hash[16],
expected[LEAP_RESPONSE_LEN];
wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Response");
resp = (struct eap_hdr *) reqData;
pos = (u8 *) (resp + 1);
resp = (const struct eap_hdr *) reqData;
pos = (const u8 *) (resp + 1);
if (reqDataLen < sizeof(*resp) + 4 || *pos != EAP_TYPE_LEAP) {
wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Response frame");
ret->ignore = TRUE;
@ -270,11 +275,11 @@ static u8 * eap_leap_process_response(struct eap_sm *sm, void *priv,
static u8 * eap_leap_process(struct eap_sm *sm, void *priv,
struct eap_method_ret *ret,
u8 *reqData, size_t reqDataLen,
const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
struct wpa_ssid *config = eap_get_config(sm);
struct eap_hdr *eap;
const struct eap_hdr *eap;
size_t len;
if (config == NULL || config->password == NULL) {
@ -284,7 +289,7 @@ static u8 * eap_leap_process(struct eap_sm *sm, void *priv,
return NULL;
}
eap = (struct eap_hdr *) reqData;
eap = (const struct eap_hdr *) reqData;
if (reqDataLen < sizeof(*eap) ||
(len = be_to_host16(eap->length)) > reqDataLen) {
@ -295,7 +300,7 @@ static u8 * eap_leap_process(struct eap_sm *sm, void *priv,
ret->ignore = FALSE;
ret->allowNotifications = TRUE;
ret->methodState = METHOD_CONT;
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
sm->leap_done = FALSE;
@ -331,7 +336,8 @@ static u8 * eap_leap_getKey(struct eap_sm *sm, void *priv, size_t *len)
struct eap_leap_data *data = priv;
struct wpa_ssid *config = eap_get_config(sm);
u8 *key, pw_hash_hash[16], pw_hash[16];
MD5_CTX context;
const u8 *addr[5];
size_t elen[5];
if (data->state != LEAP_DONE)
return NULL;
@ -353,13 +359,17 @@ static u8 * eap_leap_getKey(struct eap_sm *sm, void *priv, size_t *len)
wpa_hexdump(MSG_DEBUG, "EAP-LEAP: ap_response",
data->ap_response, LEAP_RESPONSE_LEN);
MD5Init(&context);
MD5Update(&context, pw_hash_hash, 16);
MD5Update(&context, data->ap_challenge, LEAP_CHALLENGE_LEN);
MD5Update(&context, data->ap_response, LEAP_RESPONSE_LEN);
MD5Update(&context, data->peer_challenge, LEAP_CHALLENGE_LEN);
MD5Update(&context, data->peer_response, LEAP_RESPONSE_LEN);
MD5Final(key, &context);
addr[0] = pw_hash_hash;
elen[0] = 16;
addr[1] = data->ap_challenge;
elen[1] = LEAP_CHALLENGE_LEN;
addr[2] = data->ap_response;
elen[2] = LEAP_RESPONSE_LEN;
addr[3] = data->peer_challenge;
elen[3] = LEAP_CHALLENGE_LEN;
addr[4] = data->peer_response;
elen[4] = LEAP_RESPONSE_LEN;
md5_vector(5, addr, elen, key);
wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: master key", key, LEAP_KEY_LEN);
*len = LEAP_KEY_LEN;

View file

@ -20,6 +20,7 @@
#include "wpa_supplicant.h"
#include "config_ssid.h"
#include "md5.h"
#include "crypto.h"
static void * eap_md5_init(struct eap_sm *sm)
@ -35,15 +36,18 @@ static void eap_md5_deinit(struct eap_sm *sm, void *priv)
static u8 * eap_md5_process(struct eap_sm *sm, void *priv,
struct eap_method_ret *ret,
u8 *reqData, size_t reqDataLen,
const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
struct wpa_ssid *config = eap_get_config(sm);
struct eap_hdr *req, *resp;
u8 *pos, *challenge;
const struct eap_hdr *req;
struct eap_hdr *resp;
const u8 *pos, *challenge;
u8 *rpos;
int challenge_len;
MD5_CTX context;
size_t len;
const u8 *addr[3];
size_t elen[3];
if (config == NULL || config->password == NULL) {
wpa_printf(MSG_INFO, "EAP-MD5: Password not configured");
@ -52,18 +56,15 @@ static u8 * eap_md5_process(struct eap_sm *sm, void *priv,
return NULL;
}
req = (struct eap_hdr *) reqData;
pos = (u8 *) (req + 1);
if (reqDataLen < sizeof(*req) + 2 || *pos != EAP_TYPE_MD5 ||
(len = be_to_host16(req->length)) > reqDataLen) {
wpa_printf(MSG_INFO, "EAP-MD5: Invalid frame");
pos = eap_hdr_validate(EAP_TYPE_MD5, reqData, reqDataLen, &len);
if (pos == NULL) {
ret->ignore = TRUE;
return NULL;
}
pos++;
req = (const struct eap_hdr *) reqData;
challenge_len = *pos++;
if (challenge_len == 0 ||
challenge_len > len - sizeof(*req) - 2) {
challenge_len > len - 1) {
wpa_printf(MSG_INFO, "EAP-MD5: Invalid challenge "
"(challenge_len=%d len=%lu",
challenge_len, (unsigned long) len);
@ -87,16 +88,18 @@ static u8 * eap_md5_process(struct eap_sm *sm, void *priv,
resp->code = EAP_CODE_RESPONSE;
resp->identifier = req->identifier;
resp->length = host_to_be16(*respDataLen);
pos = (u8 *) (resp + 1);
*pos++ = EAP_TYPE_MD5;
*pos++ = MD5_MAC_LEN; /* Value-Size */
rpos = (u8 *) (resp + 1);
*rpos++ = EAP_TYPE_MD5;
*rpos++ = MD5_MAC_LEN; /* Value-Size */
MD5Init(&context);
MD5Update(&context, &resp->identifier, 1);
MD5Update(&context, config->password, config->password_len);
MD5Update(&context, challenge, challenge_len);
MD5Final(pos, &context);
wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Response", pos, MD5_MAC_LEN);
addr[0] = &resp->identifier;
elen[0] = 1;
addr[1] = config->password;
elen[1] = config->password_len;
addr[2] = challenge;
elen[2] = challenge_len;
md5_vector(3, addr, elen, rpos);
wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Response", rpos, MD5_MAC_LEN);
return (u8 *) resp;
}

View file

@ -21,6 +21,7 @@
#include "wpa_supplicant.h"
#include "config_ssid.h"
#include "ms_funcs.h"
#include "wpa_ctrl.h"
struct eap_mschapv2_hdr {
@ -71,6 +72,9 @@ struct eap_mschapv2_data {
u8 master_key[16];
int master_key_valid;
int success;
u8 *prev_challenge;
size_t prev_challenge_len;
};
@ -114,6 +118,7 @@ static void eap_mschapv2_deinit(struct eap_sm *sm, void *priv)
struct eap_mschapv2_data *data = priv;
free(data->peer_challenge);
free(data->auth_challenge);
free(data->prev_challenge);
free(data);
}
@ -121,7 +126,7 @@ static void eap_mschapv2_deinit(struct eap_sm *sm, void *priv)
static u8 * eap_mschapv2_challenge(struct eap_sm *sm,
struct eap_mschapv2_data *data,
struct eap_method_ret *ret,
struct eap_mschapv2_hdr *req,
const struct eap_mschapv2_hdr *req,
size_t *respDataLen)
{
struct wpa_ssid *config = eap_get_config(sm);
@ -131,6 +136,9 @@ static u8 * eap_mschapv2_challenge(struct eap_sm *sm,
struct eap_mschapv2_hdr *resp;
u8 password_hash[16], password_hash_hash[16];
if (config == NULL)
return NULL;
/* MSCHAPv2 does not include optional domain name in the
* challenge-response calculation, so remove domain prefix
* (if present). */
@ -150,26 +158,31 @@ static u8 * eap_mschapv2_challenge(struct eap_sm *sm,
challenge_len = *pos++;
if (challenge_len != 16) {
wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid challenge length "
"%d", challenge_len);
"%lu", (unsigned long) challenge_len);
ret->ignore = TRUE;
return NULL;
}
if (len < 10 || len - 10 < challenge_len) {
wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Too short challenge"
" packet: len=%lu challenge_len=%d",
(unsigned long) len, challenge_len);
" packet: len=%lu challenge_len=%lu",
(unsigned long) len, (unsigned long) challenge_len);
ret->ignore = TRUE;
return NULL;
}
challenge = pos;
if (data->passwd_change_challenge_valid) {
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Using challenge from the "
"failure message");
challenge = data->passwd_change_challenge;
} else
challenge = pos;
pos += challenge_len;
wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Authentication Servername",
pos, len - challenge_len - 10);
ret->ignore = FALSE;
ret->methodState = METHOD_CONT;
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
ret->allowNotifications = TRUE;
@ -187,9 +200,17 @@ static u8 * eap_mschapv2_challenge(struct eap_sm *sm,
resp->type = EAP_TYPE_MSCHAPV2;
resp->op_code = MSCHAPV2_OP_RESPONSE;
resp->mschapv2_id = req->mschapv2_id;
if (data->prev_error) {
/*
* TODO: this does not seem to be enough when processing two
* or more failure messages. IAS did not increment mschapv2_id
* in its own packets, but it seemed to expect the peer to
* increment this for all packets(?).
*/
resp->mschapv2_id++;
}
ms_len = *respDataLen - 5;
resp->ms_length[0] = ms_len >> 8;
resp->ms_length[1] = ms_len & 0xff;
WPA_PUT_BE16(resp->ms_length, ms_len);
pos = (u8 *) (resp + 1);
*pos++ = MSCHAPV2_RESP_LEN; /* Value-Size */
@ -243,6 +264,8 @@ static u8 * eap_mschapv2_challenge(struct eap_sm *sm,
pos++; /* Flag / reserved, must be zero */
memcpy(pos, config->identity, config->identity_len);
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: TX identifier %d mschapv2_id %d "
"(response)", resp->identifier, resp->mschapv2_id);
return (u8 *) resp;
}
@ -250,16 +273,17 @@ static u8 * eap_mschapv2_challenge(struct eap_sm *sm,
static u8 * eap_mschapv2_success(struct eap_sm *sm,
struct eap_mschapv2_data *data,
struct eap_method_ret *ret,
struct eap_mschapv2_hdr *req,
const struct eap_mschapv2_hdr *req,
size_t *respDataLen)
{
struct eap_mschapv2_hdr *resp;
u8 *pos, recv_response[20];
const u8 *pos;
u8 recv_response[20];
int len, left;
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received success");
len = be_to_host16(req->length);
pos = (u8 *) (req + 1);
pos = (const u8 *) (req + 1);
if (!data->auth_response_valid || len < sizeof(*req) + 42 ||
pos[0] != 'S' || pos[1] != '=' ||
hexstr2bin((char *) (pos + 2), recv_response, 20) ||
@ -299,6 +323,21 @@ static u8 * eap_mschapv2_success(struct eap_sm *sm,
ret->allowNotifications = FALSE;
data->success = 1;
if (data->prev_error == ERROR_PASSWD_EXPIRED) {
struct wpa_ssid *config = eap_get_config(sm);
if (config && config->new_password) {
wpa_msg(sm->msg_ctx, MSG_INFO,
WPA_EVENT_PASSWORD_CHANGED
"EAP-MSCHAPV2: Password changed successfully");
data->prev_error = 0;
free(config->password);
config->password = config->new_password;
config->new_password = NULL;
config->password_len = config->new_password_len;
config->new_password_len = 0;
}
}
return (u8 *) resp;
}
@ -382,27 +421,152 @@ static int eap_mschapv2_failure_txt(struct eap_sm *sm,
"EAP-MSCHAPV2: failure message: '%s' (retry %sallowed, error "
"%d)",
msg, retry == 1 ? "" : "not ", data->prev_error);
if (retry == 1 && config) {
if (data->prev_error == ERROR_PASSWD_EXPIRED &&
data->passwd_change_version == 3 && config) {
if (config->new_password == NULL) {
wpa_msg(sm->msg_ctx, MSG_INFO,
"EAP-MSCHAPV2: Password expired - password "
"change required");
eap_sm_request_new_password(sm, config);
}
} else if (retry == 1 && config) {
/* TODO: could prevent the current password from being used
* again at least for some period of time */
eap_sm_request_identity(sm, config);
if (!config->mschapv2_retry)
eap_sm_request_identity(sm, config);
eap_sm_request_password(sm, config);
config->mschapv2_retry = 1;
} else if (config) {
/* TODO: prevent retries using same username/password */
config->mschapv2_retry = 0;
}
return retry == 1;
}
static u8 * eap_mschapv2_change_password(struct eap_sm *sm,
struct eap_mschapv2_data *data,
struct eap_method_ret *ret,
const struct eap_mschapv2_hdr *req,
size_t *respDataLen)
{
struct eap_mschapv2_hdr *resp;
int ms_len, i;
u8 *peer_challenge, *username, *pos;
size_t username_len;
struct wpa_ssid *config = eap_get_config(sm);
if (config == NULL || config->identity == NULL ||
config->new_password == NULL || config->password == NULL)
return NULL;
/*
* MSCHAPv2 does not include optional domain name in the
* challenge-response calculation, so remove domain prefix
* (if present).
*/
username = config->identity;
username_len = config->identity_len;
for (i = 0; i < username_len; i++) {
if (username[i] == '\\') {
username_len -= i + 1;
username += i + 1;
break;
}
}
ret->ignore = FALSE;
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_COND_SUCC;
ret->allowNotifications = TRUE;
*respDataLen = 591;
resp = malloc(*respDataLen);
if (resp == NULL) {
return NULL;
}
resp->code = EAP_CODE_RESPONSE;
resp->identifier = req->identifier;
resp->length = host_to_be16((u16) *respDataLen);
resp->type = EAP_TYPE_MSCHAPV2;
resp->op_code = MSCHAPV2_OP_CHANGE_PASSWORD;
resp->mschapv2_id = req->mschapv2_id + 1;
ms_len = *respDataLen - 5;
WPA_PUT_BE16(resp->ms_length, ms_len);
pos = (u8 *) (resp + 1);
/* Encrypted-Password */
new_password_encrypted_with_old_nt_password_hash(
config->new_password, config->new_password_len,
config->password, config->password_len, pos);
pos += 516;
/* Encrypted-Hash */
old_nt_password_hash_encrypted_with_new_nt_password_hash(
config->new_password, config->new_password_len,
config->password, config->password_len, pos);
pos += 16;
/* Peer-Challenge */
peer_challenge = pos;
if (hostapd_get_rand(peer_challenge, 16)) {
free(resp);
return NULL;
}
pos += 16;
/* Reserved, must be zero */
memset(pos, 0, 8);
pos += 8;
/* NT-Response */
wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: auth_challenge",
data->passwd_change_challenge, PASSWD_CHANGE_CHAL_LEN);
wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: peer_challenge",
peer_challenge, 16);
wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: username",
username, username_len);
wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-MSCHAPV2: new password",
config->new_password, config->new_password_len);
generate_nt_response(data->passwd_change_challenge, peer_challenge,
username, username_len,
config->new_password, config->new_password_len,
pos);
wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: NT-Response", pos, 24);
/* Authenticator response is not really needed yet, but calculate it
* here so that challenges need not be saved. */
generate_authenticator_response(config->new_password,
config->new_password_len,
peer_challenge,
data->passwd_change_challenge,
username, username_len, pos,
data->auth_response);
data->auth_response_valid = 1;
pos += 24;
/* Flags */
*pos++ = 0;
*pos++ = 0;
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: TX identifier %d mschapv2_id %d "
"(change pw)", resp->identifier, resp->mschapv2_id);
return (u8 *) resp;
}
static u8 * eap_mschapv2_failure(struct eap_sm *sm,
struct eap_mschapv2_data *data,
struct eap_method_ret *ret,
struct eap_mschapv2_hdr *req,
const struct eap_mschapv2_hdr *req,
size_t *respDataLen)
{
struct eap_mschapv2_hdr *resp;
u8 *msdata = (u8 *) (req + 1);
const u8 *msdata = (const u8 *) (req + 1);
char *buf;
int len = be_to_host16(req->length) - sizeof(*req);
int retry = 0;
@ -423,10 +587,19 @@ static u8 * eap_mschapv2_failure(struct eap_sm *sm,
ret->decision = DECISION_FAIL;
ret->allowNotifications = FALSE;
if (retry) {
if (data->prev_error == ERROR_PASSWD_EXPIRED &&
data->passwd_change_version == 3) {
struct wpa_ssid *config = eap_get_config(sm);
if (config && config->new_password)
return eap_mschapv2_change_password(sm, data, ret, req,
respDataLen);
if (config && config->pending_req_new_password)
return NULL;
} else if (retry && data->prev_error == ERROR_AUTHENTICATION_FAILURE) {
/* TODO: could try to retry authentication, e.g, after having
* changed the username/password. In this case, EAP MS-CHAP-v2
* Failure Response would not be sent here. */
return NULL;
}
*respDataLen = 6;
@ -447,13 +620,15 @@ static u8 * eap_mschapv2_failure(struct eap_sm *sm,
static u8 * eap_mschapv2_process(struct eap_sm *sm, void *priv,
struct eap_method_ret *ret,
u8 *reqData, size_t reqDataLen,
const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
struct eap_mschapv2_data *data = priv;
struct wpa_ssid *config = eap_get_config(sm);
struct eap_mschapv2_hdr *req;
int ms_len, len;
const struct eap_mschapv2_hdr *req;
int ms_len, using_prev_challenge = 0;
const u8 *pos;
size_t len;
if (config == NULL || config->identity == NULL) {
wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Identity not configured");
@ -469,19 +644,28 @@ static u8 * eap_mschapv2_process(struct eap_sm *sm, void *priv,
return NULL;
}
req = (struct eap_mschapv2_hdr *) reqData;
len = be_to_host16(req->length);
if (len < sizeof(*req) + 2 || req->type != EAP_TYPE_MSCHAPV2 ||
len > reqDataLen) {
wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid frame");
if (config->mschapv2_retry && data->prev_challenge &&
data->prev_error == ERROR_AUTHENTICATION_FAILURE) {
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Replacing pending packet "
"with the previous challenge");
reqData = data->prev_challenge;
reqDataLen = data->prev_challenge_len;
using_prev_challenge = 1;
config->mschapv2_retry = 0;
}
pos = eap_hdr_validate(EAP_TYPE_MSCHAPV2, reqData, reqDataLen, &len);
if (pos == NULL || len < 5) {
ret->ignore = TRUE;
return NULL;
}
ms_len = ((int) req->ms_length[0] << 8) | req->ms_length[1];
req = (const struct eap_mschapv2_hdr *) reqData;
len = be_to_host16(req->length);
ms_len = WPA_GET_BE16(req->ms_length);
if (ms_len != len - 5) {
wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid header: len=%d "
"ms_len=%d", len, ms_len);
wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid header: len=%lu "
"ms_len=%d", (unsigned long) len, ms_len);
if (sm->workaround) {
/* Some authentication servers use invalid ms_len,
* ignore it for interoperability. */
@ -493,8 +677,19 @@ static u8 * eap_mschapv2_process(struct eap_sm *sm, void *priv,
}
}
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: RX identifier %d mschapv2_id %d",
req->identifier, req->mschapv2_id);
switch (req->op_code) {
case MSCHAPV2_OP_CHALLENGE:
if (!using_prev_challenge) {
free(data->prev_challenge);
data->prev_challenge = malloc(len);
if (data->prev_challenge) {
data->prev_challenge_len = len;
memcpy(data->prev_challenge, reqData, len);
}
}
return eap_mschapv2_challenge(sm, data, ret, req, respDataLen);
case MSCHAPV2_OP_SUCCESS:
return eap_mschapv2_success(sm, data, ret, req, respDataLen);

View file

@ -35,31 +35,29 @@ static void eap_otp_deinit(struct eap_sm *sm, void *priv)
static u8 * eap_otp_process(struct eap_sm *sm, void *priv,
struct eap_method_ret *ret,
u8 *reqData, size_t reqDataLen,
const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
struct wpa_ssid *config = eap_get_config(sm);
struct eap_hdr *req, *resp;
u8 *pos, *password;
const struct eap_hdr *req;
struct eap_hdr *resp;
const u8 *pos, *password;
u8 *rpos;
size_t password_len, len;
req = (struct eap_hdr *) reqData;
pos = (u8 *) (req + 1);
if (reqDataLen < sizeof(*req) + 1 || *pos != EAP_TYPE_OTP ||
(len = be_to_host16(req->length)) > reqDataLen) {
wpa_printf(MSG_INFO, "EAP-OTP: Invalid frame");
pos = eap_hdr_validate(EAP_TYPE_OTP, reqData, reqDataLen, &len);
if (pos == NULL) {
ret->ignore = TRUE;
return NULL;
}
pos++;
req = (const struct eap_hdr *) reqData;
wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-OTP: Request message",
pos, len - sizeof(*req) - 1);
pos, len);
if (config == NULL ||
(config->password == NULL && config->otp == NULL)) {
wpa_printf(MSG_INFO, "EAP-OTP: Password not configured");
eap_sm_request_otp(sm, config, (char *) pos,
len - sizeof(*req) - 1);
eap_sm_request_otp(sm, config, (const char *) pos, len);
ret->ignore = TRUE;
return NULL;
}
@ -85,9 +83,9 @@ static u8 * eap_otp_process(struct eap_sm *sm, void *priv,
resp->code = EAP_CODE_RESPONSE;
resp->identifier = req->identifier;
resp->length = host_to_be16(*respDataLen);
pos = (u8 *) (resp + 1);
*pos++ = EAP_TYPE_OTP;
memcpy(pos, password, password_len);
rpos = (u8 *) (resp + 1);
*rpos++ = EAP_TYPE_OTP;
memcpy(rpos, password, password_len);
wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-OTP: Response",
password, password_len);

View file

@ -0,0 +1,510 @@
/*
* WPA Supplicant / EAP-PAX (draft-clancy-eap-pax-04.txt)
* Copyright (c) 2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "common.h"
#include "eap_i.h"
#include "wpa_supplicant.h"
#include "config_ssid.h"
#include "eap_pax_common.h"
#include "sha1.h"
#include "crypto.h"
/*
* Note: only PAX_STD subprotocol is currently supported
*/
struct eap_pax_data {
enum { PAX_INIT, PAX_STD_2_SENT, PAX_DONE } state;
u8 mac_id, dh_group_id, public_key_id;
union {
u8 e[2 * EAP_PAX_RAND_LEN];
struct {
u8 x[EAP_PAX_RAND_LEN]; /* server rand */
u8 y[EAP_PAX_RAND_LEN]; /* client rand */
} r;
} rand;
char *cid;
size_t cid_len;
u8 ak[EAP_PAX_AK_LEN];
u8 mk[EAP_PAX_MK_LEN];
u8 ck[EAP_PAX_CK_LEN];
u8 ick[EAP_PAX_ICK_LEN];
};
static void eap_pax_deinit(struct eap_sm *sm, void *priv);
static void * eap_pax_init(struct eap_sm *sm)
{
struct wpa_ssid *config = eap_get_config(sm);
struct eap_pax_data *data;
if (config == NULL || !config->nai ||
(!config->eappsk && !config->password)) {
wpa_printf(MSG_INFO, "EAP-PAX: CID (nai) or key "
"(eappsk/password) not configured");
return NULL;
}
if (config->eappsk && config->eappsk_len != EAP_PAX_AK_LEN) {
wpa_printf(MSG_INFO, "EAP-PAX: incorrect key length (eappsk); "
"expected %d", EAP_PAX_AK_LEN);
return NULL;
}
data = malloc(sizeof(*data));
if (data == NULL)
return NULL;
memset(data, 0, sizeof(*data));
data->state = PAX_INIT;
data->cid = malloc(config->nai_len);
if (data->cid == NULL) {
eap_pax_deinit(sm, data);
return NULL;
}
memcpy(data->cid, config->nai, config->nai_len);
data->cid_len = config->nai_len;
if (config->eappsk) {
memcpy(data->ak, config->eappsk, EAP_PAX_AK_LEN);
} else {
u8 hash[SHA1_MAC_LEN];
const unsigned char *addr[1];
size_t len[1];
addr[0] = config->password;
len[0] = config->password_len;
sha1_vector(1, addr, len, hash);
memcpy(data->ak, hash, EAP_PAX_AK_LEN);
}
return data;
}
static void eap_pax_deinit(struct eap_sm *sm, void *priv)
{
struct eap_pax_data *data = priv;
free(data->cid);
free(data);
}
static struct eap_pax_hdr * eap_pax_alloc_resp(const struct eap_pax_hdr *req,
u16 resp_len, u8 op_code)
{
struct eap_pax_hdr *resp;
resp = malloc(resp_len);
if (resp == NULL)
return NULL;
resp->code = EAP_CODE_RESPONSE;
resp->identifier = req->identifier;
resp->length = host_to_be16(resp_len);
resp->type = EAP_TYPE_PAX;
resp->op_code = op_code;
resp->flags = 0;
resp->mac_id = req->mac_id;
resp->dh_group_id = req->dh_group_id;
resp->public_key_id = req->public_key_id;
return resp;
}
static u8 * eap_pax_process_std_1(struct eap_sm *sm, struct eap_pax_data *data,
struct eap_method_ret *ret,
const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
const struct eap_pax_hdr *req;
struct eap_pax_hdr *resp;
const u8 *pos;
u8 *rpos;
size_t left;
wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-1 (received)");
req = (const struct eap_pax_hdr *) reqData;
if (data->state != PAX_INIT) {
wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-1 received in "
"unexpected state (%d) - ignored", data->state);
ret->ignore = TRUE;
return NULL;
}
if (req->flags & EAP_PAX_FLAGS_CE) {
wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-1 with CE flag set - "
"ignored");
ret->ignore = TRUE;
return NULL;
}
left = reqDataLen - sizeof(*req);
if (left < 2 + EAP_PAX_RAND_LEN) {
wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-1 with too short "
"payload");
ret->ignore = TRUE;
return NULL;
}
pos = (const u8 *) (req + 1);
if (WPA_GET_BE16(pos) != EAP_PAX_RAND_LEN) {
wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-1 with incorrect A "
"length %d (expected %d)",
WPA_GET_BE16(pos), EAP_PAX_RAND_LEN);
ret->ignore = TRUE;
return NULL;
}
pos += 2;
left -= 2;
memcpy(data->rand.r.x, pos, EAP_PAX_RAND_LEN);
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: X (server rand)",
data->rand.r.x, EAP_PAX_RAND_LEN);
pos += EAP_PAX_RAND_LEN;
left -= EAP_PAX_RAND_LEN;
if (left > 0) {
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ignored extra payload",
pos, left);
}
if (hostapd_get_rand(data->rand.r.y, EAP_PAX_RAND_LEN)) {
wpa_printf(MSG_ERROR, "EAP-PAX: Failed to get random data");
ret->ignore = TRUE;
return NULL;
}
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Y (client rand)",
data->rand.r.y, EAP_PAX_RAND_LEN);
if (eap_pax_initial_key_derivation(req->mac_id, data->ak, data->rand.e,
data->mk, data->ck, data->ick) < 0)
{
ret->ignore = TRUE;
return NULL;
}
wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-2 (sending)");
*respDataLen = sizeof(*resp) + 2 + EAP_PAX_RAND_LEN +
2 + data->cid_len + 2 + EAP_PAX_MAC_LEN + EAP_PAX_ICV_LEN;
resp = eap_pax_alloc_resp(req, *respDataLen, EAP_PAX_OP_STD_2);
if (resp == NULL)
return NULL;
rpos = (u8 *) (resp + 1);
*rpos++ = 0;
*rpos++ = EAP_PAX_RAND_LEN;
memcpy(rpos, data->rand.r.y, EAP_PAX_RAND_LEN);
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: B = Y (client rand)",
rpos, EAP_PAX_RAND_LEN);
rpos += EAP_PAX_RAND_LEN;
WPA_PUT_BE16(rpos, data->cid_len);
rpos += 2;
memcpy(rpos, data->cid, data->cid_len);
wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-PAX: CID", rpos, data->cid_len);
rpos += data->cid_len;
*rpos++ = 0;
*rpos++ = EAP_PAX_MAC_LEN;
eap_pax_mac(req->mac_id, data->ck, EAP_PAX_CK_LEN,
data->rand.r.x, EAP_PAX_RAND_LEN,
data->rand.r.y, EAP_PAX_RAND_LEN,
(u8 *) data->cid, data->cid_len, rpos);
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(A, B, CID)",
rpos, EAP_PAX_MAC_LEN);
rpos += EAP_PAX_MAC_LEN;
eap_pax_mac(req->mac_id, data->ick, EAP_PAX_ICK_LEN,
(u8 *) resp, *respDataLen - EAP_PAX_ICV_LEN,
NULL, 0, NULL, 0, rpos);
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", rpos, EAP_PAX_ICV_LEN);
rpos += EAP_PAX_ICV_LEN;
data->state = PAX_STD_2_SENT;
data->mac_id = req->mac_id;
data->dh_group_id = req->dh_group_id;
data->public_key_id = req->public_key_id;
return (u8 *) resp;
}
static u8 * eap_pax_process_std_3(struct eap_sm *sm, struct eap_pax_data *data,
struct eap_method_ret *ret,
const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
const struct eap_pax_hdr *req;
struct eap_pax_hdr *resp;
u8 *rpos, mac[EAP_PAX_MAC_LEN];
const u8 *pos;
size_t left;
wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-3 (received)");
req = (const struct eap_pax_hdr *) reqData;
if (data->state != PAX_STD_2_SENT) {
wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-3 received in "
"unexpected state (%d) - ignored", data->state);
ret->ignore = TRUE;
return NULL;
}
if (req->flags & EAP_PAX_FLAGS_CE) {
wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-3 with CE flag set - "
"ignored");
ret->ignore = TRUE;
return NULL;
}
left = reqDataLen - sizeof(*req);
if (left < 2 + EAP_PAX_MAC_LEN) {
wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-3 with too short "
"payload");
ret->ignore = TRUE;
return NULL;
}
pos = (const u8 *) (req + 1);
if (WPA_GET_BE16(pos) != EAP_PAX_MAC_LEN) {
wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-3 with incorrect "
"MAC_CK length %d (expected %d)",
WPA_GET_BE16(pos), EAP_PAX_MAC_LEN);
ret->ignore = TRUE;
return NULL;
}
pos += 2;
left -= 2;
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(B, CID)",
pos, EAP_PAX_MAC_LEN);
eap_pax_mac(data->mac_id, data->ck, EAP_PAX_CK_LEN,
data->rand.r.y, EAP_PAX_RAND_LEN,
(u8 *) data->cid, data->cid_len, NULL, 0, mac);
if (memcmp(pos, mac, EAP_PAX_MAC_LEN) != 0) {
wpa_printf(MSG_INFO, "EAP-PAX: Invalid MAC_CK(B, CID) "
"received");
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: expected MAC_CK(B, CID)",
mac, EAP_PAX_MAC_LEN);
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
return NULL;
}
pos += EAP_PAX_MAC_LEN;
left -= EAP_PAX_MAC_LEN;
if (left > 0) {
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ignored extra payload",
pos, left);
}
wpa_printf(MSG_DEBUG, "EAP-PAX: PAX-ACK (sending)");
*respDataLen = sizeof(*resp) + EAP_PAX_ICV_LEN;
resp = eap_pax_alloc_resp(req, *respDataLen, EAP_PAX_OP_ACK);
if (resp == NULL)
return NULL;
rpos = (u8 *) (resp + 1);
eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
(u8 *) resp, *respDataLen - EAP_PAX_ICV_LEN,
NULL, 0, NULL, 0, rpos);
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", rpos, EAP_PAX_ICV_LEN);
data->state = PAX_DONE;
ret->methodState = METHOD_DONE;
ret->decision = DECISION_UNCOND_SUCC;
ret->allowNotifications = FALSE;
return (u8 *) resp;
}
static u8 * eap_pax_process(struct eap_sm *sm, void *priv,
struct eap_method_ret *ret,
const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
struct eap_pax_data *data = priv;
const struct eap_pax_hdr *req;
u8 *resp, icvbuf[EAP_PAX_ICV_LEN];
const u8 *icv, *pos;
size_t len;
u16 flen;
pos = eap_hdr_validate(EAP_TYPE_PAX, reqData, reqDataLen, &len);
if (pos == NULL || len < EAP_PAX_ICV_LEN) {
ret->ignore = TRUE;
return NULL;
}
req = (const struct eap_pax_hdr *) reqData;
flen = be_to_host16(req->length) - EAP_PAX_ICV_LEN;
wpa_printf(MSG_DEBUG, "EAP-PAX: received frame: op_code 0x%x "
"flags 0x%x mac_id 0x%x dh_group_id 0x%x "
"public_key_id 0x%x",
req->op_code, req->flags, req->mac_id, req->dh_group_id,
req->public_key_id);
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: received payload",
pos, len - EAP_PAX_ICV_LEN);
if (data->state != PAX_INIT && data->mac_id != req->mac_id) {
wpa_printf(MSG_INFO, "EAP-PAX: MAC ID changed during "
"authentication (was 0x%d, is 0x%d)",
data->mac_id, req->mac_id);
ret->ignore = TRUE;
return NULL;
}
if (data->state != PAX_INIT && data->dh_group_id != req->dh_group_id) {
wpa_printf(MSG_INFO, "EAP-PAX: DH Group ID changed during "
"authentication (was 0x%d, is 0x%d)",
data->dh_group_id, req->dh_group_id);
ret->ignore = TRUE;
return NULL;
}
if (data->state != PAX_INIT &&
data->public_key_id != req->public_key_id) {
wpa_printf(MSG_INFO, "EAP-PAX: Public Key ID changed during "
"authentication (was 0x%d, is 0x%d)",
data->public_key_id, req->public_key_id);
ret->ignore = TRUE;
return NULL;
}
/* TODO: add support for EAP_PAX_MAC_AES_CBC_MAC_128 */
if (req->mac_id != EAP_PAX_MAC_HMAC_SHA1_128) {
wpa_printf(MSG_INFO, "EAP-PAX: Unsupported MAC ID 0x%x",
req->mac_id);
ret->ignore = TRUE;
return NULL;
}
if (req->dh_group_id != EAP_PAX_DH_GROUP_NONE) {
wpa_printf(MSG_INFO, "EAP-PAX: Unsupported DH Group ID 0x%x",
req->dh_group_id);
ret->ignore = TRUE;
return NULL;
}
if (req->public_key_id != EAP_PAX_PUBLIC_KEY_NONE) {
wpa_printf(MSG_INFO, "EAP-PAX: Unsupported Public Key ID 0x%x",
req->public_key_id);
ret->ignore = TRUE;
return NULL;
}
if (req->flags & EAP_PAX_FLAGS_MF) {
/* TODO: add support for reassembling fragments */
wpa_printf(MSG_INFO, "EAP-PAX: fragmentation not supported - "
"ignored packet");
ret->ignore = TRUE;
return NULL;
}
icv = pos + len - EAP_PAX_ICV_LEN;
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", icv, EAP_PAX_ICV_LEN);
if (req->op_code == EAP_PAX_OP_STD_1) {
eap_pax_mac(req->mac_id, (u8 *) "", 0,
reqData, flen, NULL, 0, NULL, 0, icvbuf);
} else {
eap_pax_mac(req->mac_id, data->ick, EAP_PAX_ICK_LEN,
reqData, flen, NULL, 0, NULL, 0, icvbuf);
}
if (memcmp(icv, icvbuf, EAP_PAX_ICV_LEN) != 0) {
wpa_printf(MSG_DEBUG, "EAP-PAX: invalid ICV - ignoring the "
"message");
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: expected ICV",
icvbuf, EAP_PAX_ICV_LEN);
ret->ignore = TRUE;
return NULL;
}
ret->ignore = FALSE;
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
ret->allowNotifications = TRUE;
switch (req->op_code) {
case EAP_PAX_OP_STD_1:
resp = eap_pax_process_std_1(sm, data, ret, reqData, flen,
respDataLen);
break;
case EAP_PAX_OP_STD_3:
resp = eap_pax_process_std_3(sm, data, ret, reqData, flen,
respDataLen);
break;
default:
wpa_printf(MSG_DEBUG, "EAP-PAX: ignoring message with unknown "
"op_code %d", req->op_code);
ret->ignore = TRUE;
return NULL;
}
if (ret->methodState == METHOD_DONE) {
ret->allowNotifications = FALSE;
}
return resp;
}
static Boolean eap_pax_isKeyAvailable(struct eap_sm *sm, void *priv)
{
struct eap_pax_data *data = priv;
return data->state == PAX_DONE;
}
static u8 * eap_pax_getKey(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_pax_data *data = priv;
u8 *key;
if (data->state != PAX_DONE)
return NULL;
key = malloc(EAP_PAX_MSK_LEN);
if (key == NULL)
return NULL;
*len = EAP_PAX_MSK_LEN;
eap_pax_kdf(data->mac_id, data->mk, EAP_PAX_MK_LEN,
"Master Session Key", data->rand.e, 2 * EAP_PAX_RAND_LEN,
EAP_PAX_MSK_LEN, key);
return key;
}
const struct eap_method eap_method_pax =
{
.method = EAP_TYPE_PAX,
.name = "PAX",
.init = eap_pax_init,
.deinit = eap_pax_deinit,
.process = eap_pax_process,
.isKeyAvailable = eap_pax_isKeyAvailable,
.getKey = eap_pax_getKey,
};

View file

@ -0,0 +1,152 @@
/*
* WPA Supplicant / EAP-PAX shared routines
* Copyright (c) 2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "common.h"
#include "sha1.h"
#include "eap_pax_common.h"
/**
* eap_pax_kdf - PAX Key Derivation Function
* @mac_id: MAC ID (EAP_PAX_MAC_*) / currently, only HMAC_SHA1_128 is supported
* @key: Secret key (X)
* @key_len: Length of the secret key in bytes
* @identifier: Public identifier for the key (Y)
* @entropy: Exchanged entropy to seed the KDF (Z)
* @entropy_len: Length of the entropy in bytes
* @output_len: Output len in bytes (W)
* @output: Buffer for the derived key
* Returns: 0 on success, -1 failed
*
* draft-clancy-eap-pax-04.txt, chap. 2.5: PAX-KDF-W(X, Y, Z)
*/
int eap_pax_kdf(u8 mac_id, const u8 *key, size_t key_len,
const char *identifier,
const u8 *entropy, size_t entropy_len,
size_t output_len, u8 *output)
{
u8 mac[SHA1_MAC_LEN];
u8 counter, *pos;
const u8 *addr[3];
size_t len[3];
size_t num_blocks, left;
num_blocks = (output_len + EAP_PAX_MAC_LEN - 1) / EAP_PAX_MAC_LEN;
if (identifier == NULL || num_blocks >= 255)
return -1;
/* TODO: add support for EAP_PAX_MAC_AES_CBC_MAC_128 */
if (mac_id != EAP_PAX_MAC_HMAC_SHA1_128)
return -1;
addr[0] = (const u8 *) identifier;
len[0] = strlen(identifier);
addr[1] = entropy;
len[1] = entropy_len;
addr[2] = &counter;
len[2] = 1;
pos = output;
left = output_len;
for (counter = 1; counter <= (u8) num_blocks; counter++) {
size_t clen = left > EAP_PAX_MAC_LEN ? EAP_PAX_MAC_LEN : left;
hmac_sha1_vector(key, key_len, 3, addr, len, mac);
memcpy(pos, mac, clen);
pos += clen;
left -= clen;
}
return 0;
}
/**
* eap_pax_mac - EAP-PAX MAC
* @mac_id: MAC ID (EAP_PAX_MAC_*) / currently, only HMAC_SHA1_128 is supported
* @key: Secret key
* @key_len: Length of the secret key in bytes
* @data1: Optional data, first block; %NULL if not used
* @data1_len: Length of data1 in bytes
* @data2: Optional data, second block; %NULL if not used
* @data2_len: Length of data2 in bytes
* @data3: Optional data, third block; %NULL if not used
* @data3_len: Length of data3 in bytes
* @mac: Buffer for the MAC value (EAP_PAX_MAC_LEN = 16 bytes)
* Returns: 0 on success, -1 on failure
*
* Wrapper function to calculate EAP-PAX MAC.
*/
int eap_pax_mac(u8 mac_id, const u8 *key, size_t key_len,
const u8 *data1, size_t data1_len,
const u8 *data2, size_t data2_len,
const u8 *data3, size_t data3_len,
u8 *mac)
{
u8 hash[SHA1_MAC_LEN];
const u8 *addr[3];
size_t len[3];
size_t count;
/* TODO: add support for EAP_PAX_MAC_AES_CBC_MAC_128 */
if (mac_id != EAP_PAX_MAC_HMAC_SHA1_128)
return -1;
addr[0] = data1;
len[0] = data1_len;
addr[1] = data2;
len[1] = data2_len;
addr[2] = data3;
len[2] = data3_len;
count = (data1 ? 1 : 0) + (data2 ? 1 : 0) + (data3 ? 1 : 0);
hmac_sha1_vector(key, key_len, count, addr, len, hash);
memcpy(mac, hash, EAP_PAX_MAC_LEN);
return 0;
}
/**
* eap_pax_initial_key_derivation - EAP-PAX initial key derivation
* @mac_id: MAC ID (EAP_PAX_MAC_*) / currently, only HMAC_SHA1_128 is supported
* @ak: Authentication Key
* @e: Entropy
* @mk: Buffer for the derived Master Key
* @ck: Buffer for the derived Confirmation Key
* @ick: Buffer for the derived Integrity Check Key
* Returns: 0 on success, -1 on failure
*/
int eap_pax_initial_key_derivation(u8 mac_id, const u8 *ak, const u8 *e,
u8 *mk, u8 *ck, u8 *ick)
{
wpa_printf(MSG_DEBUG, "EAP-PAX: initial key derivation");
if (eap_pax_kdf(mac_id, ak, EAP_PAX_AK_LEN, "Master Key",
e, 2 * EAP_PAX_RAND_LEN, EAP_PAX_MK_LEN, mk) ||
eap_pax_kdf(mac_id, mk, EAP_PAX_MK_LEN, "Confirmation Key",
e, 2 * EAP_PAX_RAND_LEN, EAP_PAX_CK_LEN, ck) ||
eap_pax_kdf(mac_id, mk, EAP_PAX_MK_LEN, "Integrity Check Key",
e, 2 * EAP_PAX_RAND_LEN, EAP_PAX_ICK_LEN, ick))
return -1;
wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: AK", ak, EAP_PAX_AK_LEN);
wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: MK", mk, EAP_PAX_MK_LEN);
wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: CK", ck, EAP_PAX_CK_LEN);
wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: ICK", ick, EAP_PAX_ICK_LEN);
return 0;
}

View file

@ -0,0 +1,84 @@
/*
* WPA Supplicant / EAP-PAX shared routines
* Copyright (c) 2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef EAP_PAX_COMMON_H
#define EAP_PAX_COMMON_H
struct eap_pax_hdr {
u8 code;
u8 identifier;
u16 length; /* including code, identifier, and length */
u8 type; /* EAP_TYPE_PAX */
u8 op_code;
u8 flags;
u8 mac_id;
u8 dh_group_id;
u8 public_key_id;
/* Followed by variable length payload and ICV */
} __attribute__ ((packed));
/* op_code: */
enum {
EAP_PAX_OP_STD_1 = 0x01,
EAP_PAX_OP_STD_2 = 0x02,
EAP_PAX_OP_STD_3 = 0x03,
EAP_PAX_OP_SEC_1 = 0x11,
EAP_PAX_OP_SEC_2 = 0x12,
EAP_PAX_OP_SEC_3 = 0x13,
EAP_PAX_OP_SEC_4 = 0x14,
EAP_PAX_OP_SEC_5 = 0x15,
EAP_PAX_OP_ACK = 0x21
};
/* flags: */
#define EAP_PAX_FLAGS_MF 0x01
#define EAP_PAX_FLAGS_CE 0x02
/* mac_id: */
#define EAP_PAX_MAC_HMAC_SHA1_128 0x01
#define EAP_PAX_MAC_AES_CBC_MAC_128 0x02
/* dh_group_id: */
#define EAP_PAX_DH_GROUP_NONE 0x00
#define EAP_PAX_DH_GROUP_3072_MODP 0x01
/* public_key_id: */
#define EAP_PAX_PUBLIC_KEY_NONE 0x00
#define EAP_PAX_PUBLIC_KEY_RSA_OAEP_2048 0x01
#define EAP_PAX_RAND_LEN 32
#define EAP_PAX_MSK_LEN 64
#define EAP_PAX_MAC_LEN 16
#define EAP_PAX_ICV_LEN 16
#define EAP_PAX_AK_LEN 16
#define EAP_PAX_MK_LEN 16
#define EAP_PAX_CK_LEN 16
#define EAP_PAX_ICK_LEN 16
int eap_pax_kdf(u8 mac_id, const u8 *key, size_t key_len,
const char *identifier,
const u8 *entropy, size_t entropy_len,
size_t output_len, u8 *output);
int eap_pax_mac(u8 mac_id, const u8 *key, size_t key_len,
const u8 *data1, size_t data1_len,
const u8 *data2, size_t data2_len,
const u8 *data3, size_t data3_len,
u8 *mac);
int eap_pax_initial_key_derivation(u8 mac_id, const u8 *ak, const u8 *e,
u8 *mk, u8 *ck, u8 *ick);
#endif /* EAP_PAX_COMMON_H */

View file

@ -193,7 +193,7 @@ static void eap_peap_deinit(struct eap_sm *sm, void *priv)
static int eap_peap_encrypt(struct eap_sm *sm, struct eap_peap_data *data,
int id, u8 *plain, size_t plain_len,
int id, const u8 *plain, size_t plain_len,
u8 **out_data, size_t *out_len)
{
int res;
@ -263,7 +263,7 @@ static int eap_peap_phase2_nak(struct eap_sm *sm,
static int eap_peap_phase2_request(struct eap_sm *sm,
struct eap_peap_data *data,
struct eap_method_ret *ret,
struct eap_hdr *req,
const struct eap_hdr *req,
struct eap_hdr *hdr,
u8 **resp, size_t *resp_len)
{
@ -348,7 +348,7 @@ static int eap_peap_phase2_request(struct eap_sm *sm,
if (*resp == NULL &&
(config->pending_req_identity || config->pending_req_password ||
config->pending_req_otp)) {
config->pending_req_otp || config->pending_req_new_password)) {
free(data->pending_phase2_req);
data->pending_phase2_req = malloc(len);
if (data->pending_phase2_req) {
@ -361,18 +361,20 @@ static int eap_peap_phase2_request(struct eap_sm *sm,
}
static int eap_peap_decrypt(struct eap_sm *sm,
struct eap_peap_data *data,
static int eap_peap_decrypt(struct eap_sm *sm, struct eap_peap_data *data,
struct eap_method_ret *ret,
struct eap_hdr *req,
u8 *in_data, size_t in_len,
const struct eap_hdr *req,
const u8 *in_data, size_t in_len,
u8 **out_data, size_t *out_len)
{
u8 *in_decrypted;
int buf_len, len_decrypted, len, skip_change = 0, res;
int buf_len, len_decrypted, len, skip_change = 0;
struct eap_hdr *hdr, *rhdr;
u8 *resp = NULL;
size_t resp_len;
const u8 *msg;
size_t msg_len;
int need_more_input;
wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for"
" Phase 2", (unsigned long) in_len);
@ -393,9 +395,10 @@ static int eap_peap_decrypt(struct eap_sm *sm,
goto continue_req;
}
res = eap_tls_data_reassemble(sm, &data->ssl, &in_data, &in_len);
if (res < 0 || res == 1)
return res;
msg = eap_tls_data_reassemble(sm, &data->ssl, in_data, in_len,
&msg_len, &need_more_input);
if (msg == NULL)
return need_more_input ? 1 : -1;
if (in_len == 0 && sm->workaround && data->phase2_success) {
/*
@ -424,7 +427,7 @@ static int eap_peap_decrypt(struct eap_sm *sm,
}
len_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
in_data, in_len,
msg, msg_len,
in_decrypted, buf_len);
free(data->ssl.tls_in);
data->ssl.tls_in = NULL;
@ -613,62 +616,22 @@ continue_req:
static u8 * eap_peap_process(struct eap_sm *sm, void *priv,
struct eap_method_ret *ret,
u8 *reqData, size_t reqDataLen,
const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
struct eap_hdr *req;
int left, res;
unsigned int tls_msg_len;
u8 flags, *pos, *resp, id;
const struct eap_hdr *req;
size_t left;
int res;
u8 flags, *resp, id;
const u8 *pos;
struct eap_peap_data *data = priv;
if (tls_get_errors(sm->ssl_ctx)) {
wpa_printf(MSG_INFO, "EAP-PEAP: TLS errors detected");
ret->ignore = TRUE;
pos = eap_tls_process_init(sm, &data->ssl, EAP_TYPE_PEAP, ret,
reqData, reqDataLen, &left, &flags);
if (pos == NULL)
return NULL;
}
req = (struct eap_hdr *) reqData;
pos = (u8 *) (req + 1);
if (reqDataLen < sizeof(*req) + 2 || *pos != EAP_TYPE_PEAP ||
(left = be_to_host16(req->length)) > reqDataLen) {
wpa_printf(MSG_INFO, "EAP-PEAP: Invalid frame");
ret->ignore = TRUE;
return NULL;
}
left -= sizeof(struct eap_hdr);
req = (const struct eap_hdr *) reqData;
id = req->identifier;
pos++;
flags = *pos++;
left -= 2;
wpa_printf(MSG_DEBUG, "EAP-PEAP: Received packet(len=%lu) - "
"Flags 0x%02x", (unsigned long) reqDataLen, flags);
if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
if (left < 4) {
wpa_printf(MSG_INFO, "EAP-PEAP: Short frame with TLS "
"length");
ret->ignore = TRUE;
return NULL;
}
tls_msg_len = (pos[0] << 24) | (pos[1] << 16) | (pos[2] << 8) |
pos[3];
wpa_printf(MSG_DEBUG, "EAP-PEAP: TLS Message Length: %d",
tls_msg_len);
if (data->ssl.tls_in_left == 0) {
data->ssl.tls_in_total = tls_msg_len;
data->ssl.tls_in_left = tls_msg_len;
free(data->ssl.tls_in);
data->ssl.tls_in = NULL;
data->ssl.tls_in_len = 0;
}
pos += 4;
left -= 4;
}
ret->ignore = FALSE;
ret->methodState = METHOD_CONT;
ret->decision = DECISION_FAIL;
ret->allowNotifications = TRUE;
if (flags & EAP_TLS_FLAGS_START) {
wpa_printf(MSG_DEBUG, "EAP-PEAP: Start (server ver=%d, own "
@ -733,12 +696,12 @@ static u8 * eap_peap_process(struct eap_sm *sm, void *priv,
"derive key");
}
if (sm->workaround && data->peap_version == 1 &&
data->resuming) {
if (sm->workaround && data->resuming) {
/*
* At least one RADIUS server (Aegis v1.1.6;
* but not v1.1.4) seems to be terminating
* PEAPv1 session resumption with outer
* At least few RADIUS servers (Aegis v1.1.6;
* but not v1.1.4; and Cisco ACS) seem to be
* terminating PEAPv1 (Aegis) or PEAPv0 (Cisco
* ACS) session resumption with outer
* EAP-Success. This does not seem to follow
* draft-josefsson-pppext-eap-tls-eap-05.txt
* section 4.2, so only allow this if EAP
@ -746,7 +709,7 @@ static u8 * eap_peap_process(struct eap_sm *sm, void *priv,
*/
wpa_printf(MSG_DEBUG, "EAP-PEAP: Workaround - "
"allow outer EAP-Success to "
"terminate PEAPv1 resumption");
"terminate PEAP resumption");
ret->decision = DECISION_COND_SUCC;
data->phase2_success = 1;
}

View file

@ -1,5 +1,5 @@
/*
* WPA Supplicant / EAP-PSK (draft-bersani-eap-psk-05.txt)
* WPA Supplicant / EAP-PSK (draft-bersani-eap-psk-09.txt)
* Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
@ -10,6 +10,9 @@
* license.
*
* See README and COPYING for more details.
*
* Note: EAP-PSK is an EAP authentication method and as such, completely
* different from WPA-PSK. This file is not needed for WPA-PSK functionality.
*/
#include <stdlib.h>
@ -22,128 +25,19 @@
#include "config_ssid.h"
#include "md5.h"
#include "aes_wrap.h"
/* draft-bersani-eap-psk-03.txt mode. This is retained for interop testing and
* will be removed once an AS that supports draft5 becomes available. */
#define EAP_PSK_DRAFT3
#define EAP_PSK_RAND_LEN 16
#define EAP_PSK_MAC_LEN 16
#define EAP_PSK_TEK_LEN 16
#define EAP_PSK_MSK_LEN 64
#define EAP_PSK_R_FLAG_CONT 1
#define EAP_PSK_R_FLAG_DONE_SUCCESS 2
#define EAP_PSK_R_FLAG_DONE_FAILURE 3
/* EAP-PSK First Message (AS -> Supplicant) */
struct eap_psk_hdr_1 {
u8 code;
u8 identifier;
u16 length; /* including code, identifier, and length */
u8 type; /* EAP_TYPE_PSK */
#ifndef EAP_PSK_DRAFT3
u8 flags;
#endif /* EAP_PSK_DRAFT3 */
u8 rand_s[EAP_PSK_RAND_LEN];
#ifndef EAP_PSK_DRAFT3
/* Followed by variable length ID_S */
#endif /* EAP_PSK_DRAFT3 */
} __attribute__ ((packed));
/* EAP-PSK Second Message (Supplicant -> AS) */
struct eap_psk_hdr_2 {
u8 code;
u8 identifier;
u16 length; /* including code, identifier, and length */
u8 type; /* EAP_TYPE_PSK */
#ifndef EAP_PSK_DRAFT3
u8 flags;
u8 rand_s[EAP_PSK_RAND_LEN];
#endif /* EAP_PSK_DRAFT3 */
u8 rand_p[EAP_PSK_RAND_LEN];
u8 mac_p[EAP_PSK_MAC_LEN];
/* Followed by variable length ID_P */
} __attribute__ ((packed));
/* EAP-PSK Third Message (AS -> Supplicant) */
struct eap_psk_hdr_3 {
u8 code;
u8 identifier;
u16 length; /* including code, identifier, and length */
u8 type; /* EAP_TYPE_PSK */
#ifndef EAP_PSK_DRAFT3
u8 flags;
u8 rand_s[EAP_PSK_RAND_LEN];
#endif /* EAP_PSK_DRAFT3 */
u8 mac_s[EAP_PSK_MAC_LEN];
/* Followed by variable length PCHANNEL */
} __attribute__ ((packed));
/* EAP-PSK Fourth Message (Supplicant -> AS) */
struct eap_psk_hdr_4 {
u8 code;
u8 identifier;
u16 length; /* including code, identifier, and length */
u8 type; /* EAP_TYPE_PSK */
#ifndef EAP_PSK_DRAFT3
u8 flags;
u8 rand_s[EAP_PSK_RAND_LEN];
#endif /* EAP_PSK_DRAFT3 */
/* Followed by variable length PCHANNEL */
} __attribute__ ((packed));
#include "eap_psk_common.h"
struct eap_psk_data {
enum { PSK_INIT, PSK_MAC_SENT, PSK_DONE } state;
u8 rand_s[EAP_PSK_RAND_LEN];
u8 rand_p[EAP_PSK_RAND_LEN];
u8 ak[16], kdk[16], tek[EAP_PSK_TEK_LEN];
u8 ak[EAP_PSK_AK_LEN], kdk[EAP_PSK_KDK_LEN], tek[EAP_PSK_TEK_LEN];
u8 *id_s, *id_p;
size_t id_s_len, id_p_len;
u8 key_data[EAP_PSK_MSK_LEN];
};
#define aes_block_size 16
static void eap_psk_key_setup(const u8 *psk, u8 *ak, u8 *kdk)
{
memset(ak, 0, aes_block_size);
aes_128_encrypt_block(psk, ak, ak);
memcpy(kdk, ak, aes_block_size);
ak[aes_block_size - 1] ^= 0x01;
kdk[aes_block_size - 1] ^= 0x02;
aes_128_encrypt_block(psk, ak, ak);
aes_128_encrypt_block(psk, kdk, kdk);
}
static void eap_psk_derive_keys(const u8 *kdk, const u8 *rb, u8 *tek, u8 *msk)
{
u8 hash[aes_block_size];
u8 counter = 1;
int i;
aes_128_encrypt_block(kdk, rb, hash);
hash[aes_block_size - 1] ^= counter;
aes_128_encrypt_block(kdk, hash, tek);
hash[aes_block_size - 1] ^= counter;
counter++;
for (i = 0; i < EAP_PSK_MSK_LEN / aes_block_size; i++) {
hash[aes_block_size - 1] ^= counter;
aes_128_encrypt_block(kdk, hash, &msk[i * aes_block_size]);
hash[aes_block_size - 1] ^= counter;
counter++;
}
}
static void * eap_psk_init(struct eap_sm *sm)
{
struct wpa_ssid *config = eap_get_config(sm);
@ -159,8 +53,8 @@ static void * eap_psk_init(struct eap_sm *sm)
return NULL;
memset(data, 0, sizeof(*data));
eap_psk_key_setup(config->eappsk, data->ak, data->kdk);
wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: AK", data->ak, 16);
wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: KDK", data->kdk, 16);
wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: AK", data->ak, EAP_PSK_AK_LEN);
wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: KDK", data->kdk, EAP_PSK_KDK_LEN);
data->state = PSK_INIT;
if (config->nai) {
@ -175,22 +69,6 @@ static void * eap_psk_init(struct eap_sm *sm)
return NULL;
}
#ifdef EAP_PSK_DRAFT3
if (config->server_nai) {
data->id_s = malloc(config->server_nai_len);
if (data->id_s)
memcpy(data->id_s, config->server_nai,
config->server_nai_len);
data->id_s_len = config->server_nai_len;
}
if (data->id_s == NULL) {
wpa_printf(MSG_INFO, "EAP-PSK: could not get server identity");
free(data->id_p);
free(data);
return NULL;
}
#endif /* EAP_PSK_DRAFT3 */
return data;
}
@ -206,17 +84,17 @@ static void eap_psk_deinit(struct eap_sm *sm, void *priv)
static u8 * eap_psk_process_1(struct eap_sm *sm, struct eap_psk_data *data,
struct eap_method_ret *ret,
u8 *reqData, size_t reqDataLen,
const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
struct eap_psk_hdr_1 *hdr1;
const struct eap_psk_hdr_1 *hdr1;
struct eap_psk_hdr_2 *hdr2;
u8 *resp, *buf, *pos;
size_t buflen;
wpa_printf(MSG_DEBUG, "EAP-PSK: in INIT state");
hdr1 = (struct eap_psk_hdr_1 *) reqData;
hdr1 = (const struct eap_psk_hdr_1 *) reqData;
if (reqDataLen < sizeof(*hdr1) ||
be_to_host16(hdr1->length) < sizeof(*hdr1) ||
be_to_host16(hdr1->length) > reqDataLen) {
@ -228,7 +106,6 @@ static u8 * eap_psk_process_1(struct eap_sm *sm, struct eap_psk_data *data,
ret->ignore = TRUE;
return NULL;
}
#ifndef EAP_PSK_DRAFT3
wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr1->flags);
if ((hdr1->flags & 0x03) != 0) {
wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 0)",
@ -237,24 +114,20 @@ static u8 * eap_psk_process_1(struct eap_sm *sm, struct eap_psk_data *data,
ret->decision = DECISION_FAIL;
return NULL;
}
#endif /* EAP_PSK_DRAFT3 */
wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr1->rand_s,
EAP_PSK_RAND_LEN);
memcpy(data->rand_s, hdr1->rand_s, EAP_PSK_RAND_LEN);
#ifndef EAP_PSK_DRAFT3
free(data->id_s);
data->id_s_len = be_to_host16(hdr1->length) - sizeof(*hdr1);
data->id_s = malloc(data->id_s_len);
if (data->id_s == NULL) {
wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory for "
"ID_S (len=%d)", data->id_s_len);
"ID_S (len=%lu)", (unsigned long) data->id_s_len);
ret->ignore = TRUE;
return NULL;
}
memcpy(data->id_s, (u8 *) (hdr1 + 1), data->id_s_len);
wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_S",
data->id_s, data->id_s_len);
#endif /* EAP_PSK_DRAFT3 */
if (hostapd_get_rand(data->rand_p, EAP_PSK_RAND_LEN)) {
wpa_printf(MSG_ERROR, "EAP-PSK: Failed to get random data");
@ -271,10 +144,8 @@ static u8 * eap_psk_process_1(struct eap_sm *sm, struct eap_psk_data *data,
hdr2->identifier = hdr1->identifier;
hdr2->length = host_to_be16(*respDataLen);
hdr2->type = EAP_TYPE_PSK;
#ifndef EAP_PSK_DRAFT3
hdr2->flags = 1; /* T=1 */
memcpy(hdr2->rand_s, hdr1->rand_s, EAP_PSK_RAND_LEN);
#endif /* EAP_PSK_DRAFT3 */
memcpy(hdr2->rand_p, data->rand_p, EAP_PSK_RAND_LEN);
memcpy((u8 *) (hdr2 + 1), data->id_p, data->id_p_len);
/* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */
@ -288,7 +159,7 @@ static u8 * eap_psk_process_1(struct eap_sm *sm, struct eap_psk_data *data,
pos = buf + data->id_p_len;
memcpy(pos, data->id_s, data->id_s_len);
pos += data->id_s_len;
memcpy(pos, data->rand_s, EAP_PSK_RAND_LEN);
memcpy(pos, hdr1->rand_s, EAP_PSK_RAND_LEN);
pos += EAP_PSK_RAND_LEN;
memcpy(pos, data->rand_p, EAP_PSK_RAND_LEN);
omac1_aes_128(data->ak, buf, buflen, hdr2->mac_p);
@ -307,19 +178,20 @@ static u8 * eap_psk_process_1(struct eap_sm *sm, struct eap_psk_data *data,
static u8 * eap_psk_process_3(struct eap_sm *sm, struct eap_psk_data *data,
struct eap_method_ret *ret,
u8 *reqData, size_t reqDataLen,
const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
struct eap_psk_hdr_3 *hdr3;
const struct eap_psk_hdr_3 *hdr3;
struct eap_psk_hdr_4 *hdr4;
u8 *resp, *buf, *pchannel, *tag, *msg, nonce[16];
u8 *resp, *buf, *rpchannel, nonce[16], *decrypted;
const u8 *pchannel, *tag, *msg;
u8 mac[EAP_PSK_MAC_LEN];
size_t buflen, left;
size_t buflen, left, data_len;
int failed = 0;
wpa_printf(MSG_DEBUG, "EAP-PSK: in MAC_SENT state");
hdr3 = (struct eap_psk_hdr_3 *) reqData;
hdr3 = (const struct eap_psk_hdr_3 *) reqData;
left = be_to_host16(hdr3->length);
if (left < sizeof(*hdr3) || reqDataLen < left) {
wpa_printf(MSG_INFO, "EAP-PSK: Invalid third message "
@ -331,8 +203,7 @@ static u8 * eap_psk_process_3(struct eap_sm *sm, struct eap_psk_data *data,
return NULL;
}
left -= sizeof(*hdr3);
pchannel = (u8 *) (hdr3 + 1);
#ifndef EAP_PSK_DRAFT3
pchannel = (const u8 *) (hdr3 + 1);
wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr3->flags);
if ((hdr3->flags & 0x03) != 2) {
wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 2)",
@ -343,16 +214,6 @@ static u8 * eap_psk_process_3(struct eap_sm *sm, struct eap_psk_data *data,
}
wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr3->rand_s,
EAP_PSK_RAND_LEN);
/* TODO: would not need to store RAND_S since it is available in this
* message. For now, since we store this anyway, verify that it matches
* with whatever the server is sending. */
if (memcmp(hdr3->rand_s, data->rand_s, EAP_PSK_RAND_LEN) != 0) {
wpa_printf(MSG_ERROR, "EAP-PSK: RAND_S did not match");
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
return NULL;
}
#endif /* EAP_PSK_DRAFT3 */
wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_S", hdr3->mac_s, EAP_PSK_MAC_LEN);
wpa_hexdump(MSG_DEBUG, "EAP-PSK: PCHANNEL", pchannel, left);
@ -404,25 +265,29 @@ static u8 * eap_psk_process_3(struct eap_sm *sm, struct eap_psk_data *data,
wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - hdr", reqData, 5);
wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - cipher msg", msg, left);
#ifdef EAP_PSK_DRAFT3
decrypted = malloc(left);
if (decrypted == NULL) {
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
return NULL;
}
memcpy(decrypted, msg, left);
if (aes_128_eax_decrypt(data->tek, nonce, sizeof(nonce),
reqData, 5, msg, left, tag))
#else /* EAP_PSK_DRAFT3 */
if (aes_128_eax_decrypt(data->tek, nonce, sizeof(nonce),
reqData, 22, msg, left, tag))
#endif /* EAP_PSK_DRAFT3 */
{
reqData, 22, decrypted, left, tag)) {
wpa_printf(MSG_WARNING, "EAP-PSK: PCHANNEL decryption failed");
free(decrypted);
return NULL;
}
wpa_hexdump(MSG_DEBUG, "EAP-PSK: Decrypted PCHANNEL message",
msg, left);
decrypted, left);
/* Verify R flag */
switch (msg[0] >> 6) {
switch (decrypted[0] >> 6) {
case EAP_PSK_R_FLAG_CONT:
wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - CONT - unsupported");
return NULL;
failed = 1;
break;
case EAP_PSK_R_FLAG_DONE_SUCCESS:
wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_SUCCESS");
break;
@ -435,37 +300,48 @@ static u8 * eap_psk_process_3(struct eap_sm *sm, struct eap_psk_data *data,
}
*respDataLen = sizeof(*hdr4) + 4 + 16 + 1;
resp = malloc(*respDataLen);
if (resp == NULL)
resp = malloc(*respDataLen + 1);
if (resp == NULL) {
free(decrypted);
return NULL;
}
hdr4 = (struct eap_psk_hdr_4 *) resp;
hdr4->code = EAP_CODE_RESPONSE;
hdr4->identifier = hdr3->identifier;
hdr4->length = host_to_be16(*respDataLen);
hdr4->type = EAP_TYPE_PSK;
#ifndef EAP_PSK_DRAFT3
hdr4->flags = 3; /* T=3 */
memcpy(hdr4->rand_s, hdr3->rand_s, EAP_PSK_RAND_LEN);
#endif /* EAP_PSK_DRAFT3 */
pchannel = (u8 *) (hdr4 + 1);
rpchannel = (u8 *) (hdr4 + 1);
/* nonce++ */
inc_byte_array(nonce, sizeof(nonce));
memcpy(pchannel, nonce + 12, 4);
memcpy(rpchannel, nonce + 12, 4);
pchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_SUCCESS << 6;
data_len = 1;
if (decrypted[0] & EAP_PSK_E_FLAG) {
wpa_printf(MSG_DEBUG, "EAP-PSK: Unsupported E (Ext) flag");
failed = 1;
rpchannel[4 + 16] = (EAP_PSK_R_FLAG_DONE_FAILURE << 6) |
EAP_PSK_E_FLAG;
if (left > 1) {
/* Add empty EXT_Payload with same EXT_Type */
(*respDataLen)++;
hdr4->length = host_to_be16(*respDataLen);
rpchannel[4 + 16 + 1] = decrypted[1];
data_len++;
}
} else if (failed)
rpchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_FAILURE << 6;
else
rpchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_SUCCESS << 6;
wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (plaintext)",
pchannel + 4 + 16, 1);
#ifdef EAP_PSK_DRAFT3
aes_128_eax_encrypt(data->tek, nonce, sizeof(nonce), resp, 5,
pchannel + 4 + 16, 1, pchannel + 4);
#else /* EAP_PSK_DRAFT3 */
rpchannel + 4 + 16, data_len);
aes_128_eax_encrypt(data->tek, nonce, sizeof(nonce), resp, 22,
pchannel + 4 + 16, 1, pchannel + 4);
#endif /* EAP_PSK_DRAFT3 */
rpchannel + 4 + 16, data_len, rpchannel + 4);
wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (PCHANNEL)",
pchannel, 4 + 16 + 1);
rpchannel, 4 + 16 + data_len);
wpa_printf(MSG_DEBUG, "EAP-PSK: Completed %ssuccessfully",
failed ? "un" : "");
@ -473,31 +349,31 @@ static u8 * eap_psk_process_3(struct eap_sm *sm, struct eap_psk_data *data,
ret->methodState = METHOD_DONE;
ret->decision = failed ? DECISION_FAIL : DECISION_UNCOND_SUCC;
free(decrypted);
return resp;
}
static u8 * eap_psk_process(struct eap_sm *sm, void *priv,
struct eap_method_ret *ret,
u8 *reqData, size_t reqDataLen,
const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
struct eap_psk_data *data = priv;
struct eap_hdr *req;
u8 *pos, *resp = NULL;
const u8 *pos;
u8 *resp = NULL;
size_t len;
req = (struct eap_hdr *) reqData;
pos = (u8 *) (req + 1);
if (reqDataLen < sizeof(*req) + 1 || *pos != EAP_TYPE_PSK ||
(len = be_to_host16(req->length)) > reqDataLen) {
wpa_printf(MSG_INFO, "EAP-PSK: Invalid frame");
pos = eap_hdr_validate(EAP_TYPE_PSK, reqData, reqDataLen, &len);
if (pos == NULL) {
ret->ignore = TRUE;
return NULL;
}
len += sizeof(struct eap_hdr) + 1;
ret->ignore = FALSE;
ret->methodState = METHOD_CONT;
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
ret->allowNotifications = TRUE;

View file

@ -0,0 +1,57 @@
/*
* WPA Supplicant / EAP-PSK shared routines
* Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "common.h"
#include "aes_wrap.h"
#include "eap_psk_common.h"
#define aes_block_size 16
void eap_psk_key_setup(const u8 *psk, u8 *ak, u8 *kdk)
{
memset(ak, 0, aes_block_size);
aes_128_encrypt_block(psk, ak, ak);
memcpy(kdk, ak, aes_block_size);
ak[aes_block_size - 1] ^= 0x01;
kdk[aes_block_size - 1] ^= 0x02;
aes_128_encrypt_block(psk, ak, ak);
aes_128_encrypt_block(psk, kdk, kdk);
}
void eap_psk_derive_keys(const u8 *kdk, const u8 *rand_p, u8 *tek, u8 *msk)
{
u8 hash[aes_block_size];
u8 counter = 1;
int i;
aes_128_encrypt_block(kdk, rand_p, hash);
hash[aes_block_size - 1] ^= counter;
aes_128_encrypt_block(kdk, hash, tek);
hash[aes_block_size - 1] ^= counter;
counter++;
for (i = 0; i < EAP_PSK_MSK_LEN / aes_block_size; i++) {
hash[aes_block_size - 1] ^= counter;
aes_128_encrypt_block(kdk, hash, &msk[i * aes_block_size]);
hash[aes_block_size - 1] ^= counter;
counter++;
}
}

View file

@ -0,0 +1,92 @@
/*
* WPA Supplicant / EAP-PSK shared routines
* Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef EAP_PSK_COMMON_H
#define EAP_PSK_COMMON_H
#define EAP_PSK_RAND_LEN 16
#define EAP_PSK_MAC_LEN 16
#define EAP_PSK_TEK_LEN 16
#define EAP_PSK_MSK_LEN 64
#define EAP_PSK_PSK_LEN 16
#define EAP_PSK_AK_LEN 16
#define EAP_PSK_KDK_LEN 16
#define EAP_PSK_R_FLAG_CONT 1
#define EAP_PSK_R_FLAG_DONE_SUCCESS 2
#define EAP_PSK_R_FLAG_DONE_FAILURE 3
#define EAP_PSK_E_FLAG 0x20
/* Shared prefix for all EAP-PSK frames */
struct eap_psk_hdr {
u8 code;
u8 identifier;
u16 length; /* including code, identifier, and length */
u8 type; /* EAP_TYPE_PSK */
u8 flags;
} __attribute__ ((packed));
/* EAP-PSK First Message (AS -> Supplicant) */
struct eap_psk_hdr_1 {
u8 code;
u8 identifier;
u16 length; /* including code, identifier, and length */
u8 type; /* EAP_TYPE_PSK */
u8 flags;
u8 rand_s[EAP_PSK_RAND_LEN];
/* Followed by variable length ID_S */
} __attribute__ ((packed));
/* EAP-PSK Second Message (Supplicant -> AS) */
struct eap_psk_hdr_2 {
u8 code;
u8 identifier;
u16 length; /* including code, identifier, and length */
u8 type; /* EAP_TYPE_PSK */
u8 flags;
u8 rand_s[EAP_PSK_RAND_LEN];
u8 rand_p[EAP_PSK_RAND_LEN];
u8 mac_p[EAP_PSK_MAC_LEN];
/* Followed by variable length ID_P */
} __attribute__ ((packed));
/* EAP-PSK Third Message (AS -> Supplicant) */
struct eap_psk_hdr_3 {
u8 code;
u8 identifier;
u16 length; /* including code, identifier, and length */
u8 type; /* EAP_TYPE_PSK */
u8 flags;
u8 rand_s[EAP_PSK_RAND_LEN];
u8 mac_s[EAP_PSK_MAC_LEN];
/* Followed by variable length PCHANNEL */
} __attribute__ ((packed));
/* EAP-PSK Fourth Message (Supplicant -> AS) */
struct eap_psk_hdr_4 {
u8 code;
u8 identifier;
u16 length; /* including code, identifier, and length */
u8 type; /* EAP_TYPE_PSK */
u8 flags;
u8 rand_s[EAP_PSK_RAND_LEN];
/* Followed by variable length PCHANNEL */
} __attribute__ ((packed));
void eap_psk_key_setup(const u8 *psk, u8 *ak, u8 *kdk);
void eap_psk_derive_keys(const u8 *kdk, const u8 *rand_p, u8 *tek, u8 *msk);
#endif /* EAP_PSK_COMMON_H */

View file

@ -20,7 +20,7 @@
#include "eap_i.h"
#include "wpa_supplicant.h"
#include "config_ssid.h"
#include "sha1.h"
#include "crypto.h"
#include "pcsc_funcs.h"
#include "eap_sim_common.h"
@ -198,8 +198,7 @@ static void eap_sim_derive_mk(struct eap_sim_data *data,
addr[4] = sel_ver;
len[4] = 2;
sel_ver[0] = data->selected_version >> 8;
sel_ver[1] = data->selected_version & 0xff;
WPA_PUT_BE16(sel_ver, data->selected_version);
/* MK = SHA1(Identity|n*Kc|NONCE_MT|Version List|Selected Version) */
sha1_vector(5, addr, len, data->mk);
@ -277,7 +276,7 @@ static int eap_sim_learn_ids(struct eap_sim_data *data,
static u8 * eap_sim_client_error(struct eap_sm *sm, struct eap_sim_data *data,
struct eap_hdr *req,
const struct eap_hdr *req,
size_t *respDataLen, int err)
{
struct eap_sim_msg *msg;
@ -295,7 +294,7 @@ static u8 * eap_sim_client_error(struct eap_sm *sm, struct eap_sim_data *data,
static u8 * eap_sim_response_start(struct eap_sm *sm,
struct eap_sim_data *data,
struct eap_hdr *req,
const struct eap_hdr *req,
size_t *respDataLen,
enum eap_sim_id_req id_req)
{
@ -324,7 +323,7 @@ static u8 * eap_sim_response_start(struct eap_sm *sm,
eap_sim_clear_identities(data, CLEAR_EAP_ID);
wpa_printf(MSG_DEBUG, "Generating EAP-SIM Start (id=%d)",
req->identifier);
req->identifier);
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, req->identifier,
EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START);
wpa_hexdump(MSG_DEBUG, " AT_NONCE_MT",
@ -349,13 +348,13 @@ static u8 * eap_sim_response_start(struct eap_sm *sm,
static u8 * eap_sim_response_challenge(struct eap_sm *sm,
struct eap_sim_data *data,
struct eap_hdr *req,
const struct eap_hdr *req,
size_t *respDataLen)
{
struct eap_sim_msg *msg;
wpa_printf(MSG_DEBUG, "Generating EAP-SIM Challenge (id=%d)",
req->identifier);
req->identifier);
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, req->identifier,
EAP_TYPE_SIM, EAP_SIM_SUBTYPE_CHALLENGE);
wpa_printf(MSG_DEBUG, " AT_MAC");
@ -368,7 +367,7 @@ static u8 * eap_sim_response_challenge(struct eap_sm *sm,
static u8 * eap_sim_response_reauth(struct eap_sm *sm,
struct eap_sim_data *data,
struct eap_hdr *req,
const struct eap_hdr *req,
size_t *respDataLen, int counter_too_small)
{
struct eap_sim_msg *msg;
@ -408,7 +407,7 @@ static u8 * eap_sim_response_reauth(struct eap_sm *sm,
static u8 * eap_sim_response_notification(struct eap_sm *sm,
struct eap_sim_data *data,
struct eap_hdr *req,
const struct eap_hdr *req,
size_t *respDataLen,
u16 notification)
{
@ -446,7 +445,7 @@ static u8 * eap_sim_response_notification(struct eap_sm *sm,
static u8 * eap_sim_process_start(struct eap_sm *sm, struct eap_sim_data *data,
struct eap_hdr *req, size_t reqDataLen,
const struct eap_hdr *req, size_t reqDataLen,
size_t *respDataLen,
struct eap_sim_attrs *attr)
{
@ -524,7 +523,8 @@ static u8 * eap_sim_process_start(struct eap_sm *sm, struct eap_sim_data *data,
static u8 * eap_sim_process_challenge(struct eap_sm *sm,
struct eap_sim_data *data,
struct eap_hdr *req, size_t reqDataLen,
const struct eap_hdr *req,
size_t reqDataLen,
size_t *respDataLen,
struct eap_sim_attrs *attr)
{
@ -595,8 +595,9 @@ static u8 * eap_sim_process_challenge(struct eap_sm *sm,
"derivation", identity, identity_len);
eap_sim_derive_mk(data, identity, identity_len);
eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk);
if (eap_sim_verify_mac(data->k_aut, (u8 *) req, reqDataLen, attr->mac,
data->nonce_mt, EAP_SIM_NONCE_MT_LEN)) {
if (eap_sim_verify_mac(data->k_aut, (const u8 *) req, reqDataLen,
attr->mac, data->nonce_mt,
EAP_SIM_NONCE_MT_LEN)) {
wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
"used invalid AT_MAC");
return eap_sim_client_error(sm, data, req, respDataLen,
@ -610,14 +611,17 @@ static u8 * eap_sim_process_challenge(struct eap_sm *sm,
CLEAR_EAP_ID);
if (attr->encr_data) {
if (eap_sim_parse_encr(data->k_encr, attr->encr_data,
attr->encr_data_len, attr->iv, &eattr,
0)) {
u8 *decrypted;
decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
attr->encr_data_len, attr->iv,
&eattr, 0);
if (decrypted == NULL) {
return eap_sim_client_error(
sm, data, req, respDataLen,
EAP_SIM_UNABLE_TO_PROCESS_PACKET);
}
eap_sim_learn_ids(data, &eattr);
free(decrypted);
}
if (data->state != FAILURE)
@ -634,11 +638,12 @@ static u8 * eap_sim_process_challenge(struct eap_sm *sm,
static int eap_sim_process_notification_reauth(struct eap_sim_data *data,
struct eap_hdr *req,
const struct eap_hdr *req,
size_t reqDataLen,
struct eap_sim_attrs *attr)
{
struct eap_sim_attrs eattr;
u8 *decrypted;
if (attr->encr_data == NULL || attr->iv == NULL) {
wpa_printf(MSG_WARNING, "EAP-SIM: Notification message after "
@ -646,8 +651,10 @@ static int eap_sim_process_notification_reauth(struct eap_sim_data *data,
return -1;
}
if (eap_sim_parse_encr(data->k_encr, attr->encr_data,
attr->encr_data_len, attr->iv, &eattr, 0)) {
decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
attr->encr_data_len, attr->iv, &eattr,
0);
if (decrypted == NULL) {
wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted "
"data from notification message");
return -1;
@ -657,15 +664,17 @@ static int eap_sim_process_notification_reauth(struct eap_sim_data *data,
wpa_printf(MSG_WARNING, "EAP-SIM: Counter in notification "
"message does not match with counter in reauth "
"message");
free(decrypted);
return -1;
}
free(decrypted);
return 0;
}
static int eap_sim_process_notification_auth(struct eap_sim_data *data,
struct eap_hdr *req,
const struct eap_hdr *req,
size_t reqDataLen,
struct eap_sim_attrs *attr)
{
@ -695,7 +704,7 @@ static int eap_sim_process_notification_auth(struct eap_sim_data *data,
static u8 * eap_sim_process_notification(struct eap_sm *sm,
struct eap_sim_data *data,
struct eap_hdr *req,
const struct eap_hdr *req,
size_t reqDataLen,
size_t *respDataLen,
struct eap_sim_attrs *attr)
@ -732,12 +741,13 @@ static u8 * eap_sim_process_notification(struct eap_sm *sm,
static u8 * eap_sim_process_reauthentication(struct eap_sm *sm,
struct eap_sim_data *data,
struct eap_hdr *req,
const struct eap_hdr *req,
size_t reqDataLen,
size_t *respDataLen,
struct eap_sim_attrs *attr)
{
struct eap_sim_attrs eattr;
u8 *decrypted;
wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Reauthentication");
@ -749,7 +759,7 @@ static u8 * eap_sim_process_reauthentication(struct eap_sm *sm,
}
data->reauth = 1;
if (eap_sim_verify_mac(data->k_aut, (u8 *) req, reqDataLen,
if (eap_sim_verify_mac(data->k_aut, (const u8 *) req, reqDataLen,
attr->mac, (u8 *) "", 0)) {
wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication "
"did not have valid AT_MAC");
@ -764,8 +774,10 @@ static u8 * eap_sim_process_reauthentication(struct eap_sm *sm,
EAP_SIM_UNABLE_TO_PROCESS_PACKET);
}
if (eap_sim_parse_encr(data->k_encr, attr->encr_data,
attr->encr_data_len, attr->iv, &eattr, 0)) {
decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
attr->encr_data_len, attr->iv, &eattr,
0);
if (decrypted == NULL) {
wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted "
"data from reauthentication message");
return eap_sim_client_error(sm, data, req, respDataLen,
@ -776,6 +788,7 @@ static u8 * eap_sim_process_reauthentication(struct eap_sm *sm,
wpa_printf(MSG_INFO, "EAP-SIM: (encr) No%s%s in reauth packet",
!eattr.nonce_s ? " AT_NONCE_S" : "",
eattr.counter < 0 ? " AT_COUNTER" : "");
free(decrypted);
return eap_sim_client_error(sm, data, req, respDataLen,
EAP_SIM_UNABLE_TO_PROCESS_PACKET);
}
@ -794,6 +807,7 @@ static u8 * eap_sim_process_reauthentication(struct eap_sm *sm,
data->last_eap_identity_len = data->reauth_id_len;
data->reauth_id = NULL;
data->reauth_id_len = 0;
free(decrypted);
return eap_sim_response_reauth(sm, data, req, respDataLen, 1);
}
data->counter = eattr.counter;
@ -818,19 +832,21 @@ static u8 * eap_sim_process_reauthentication(struct eap_sm *sm,
"fast reauths performed - force fullauth");
eap_sim_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
}
free(decrypted);
return eap_sim_response_reauth(sm, data, req, respDataLen, 0);
}
static u8 * eap_sim_process(struct eap_sm *sm, void *priv,
struct eap_method_ret *ret,
u8 *reqData, size_t reqDataLen,
const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
struct eap_sim_data *data = priv;
struct wpa_ssid *config = eap_get_config(sm);
struct eap_hdr *req;
u8 *pos, subtype, *res;
const struct eap_hdr *req;
u8 subtype, *res;
const u8 *pos;
struct eap_sim_attrs attr;
size_t len;
@ -842,21 +858,19 @@ static u8 * eap_sim_process(struct eap_sm *sm, void *priv,
return NULL;
}
req = (struct eap_hdr *) reqData;
pos = (u8 *) (req + 1);
if (reqDataLen < sizeof(*req) + 4 || *pos != EAP_TYPE_SIM ||
(len = be_to_host16(req->length)) > reqDataLen) {
wpa_printf(MSG_INFO, "EAP-SIM: Invalid frame");
pos = eap_hdr_validate(EAP_TYPE_SIM, reqData, reqDataLen, &len);
if (pos == NULL || len < 1) {
ret->ignore = TRUE;
return NULL;
}
req = (const struct eap_hdr *) reqData;
len = be_to_host16(req->length);
ret->ignore = FALSE;
ret->methodState = METHOD_CONT;
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
ret->allowNotifications = TRUE;
pos++;
subtype = *pos++;
wpa_printf(MSG_DEBUG, "EAP-SIM: Subtype=%d", subtype);
pos += 2; /* Reserved */
@ -901,7 +915,7 @@ done:
ret->decision = DECISION_FAIL;
ret->methodState = METHOD_DONE;
} else if (data->state == SUCCESS) {
ret->decision = DECISION_UNCOND_SUCC;
ret->decision = DECISION_COND_SUCC;
ret->methodState = METHOD_DONE;
}

View file

@ -19,14 +19,11 @@
#include "common.h"
#include "eap_i.h"
#include "sha1.h"
#include "crypto.h"
#include "aes_wrap.h"
#include "eap_sim_common.h"
#define MSK_LEN 8
#define EMSK_LEN 8
static void eap_sim_prf(const u8 *key, u8 *x, size_t xlen)
{
u8 xkey[64];
@ -86,22 +83,17 @@ void eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk)
memcpy(k_aut, pos, EAP_SIM_K_AUT_LEN);
pos += EAP_SIM_K_AUT_LEN;
memcpy(msk, pos, EAP_SIM_KEYING_DATA_LEN);
pos += MSK_LEN;
wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_encr",
k_encr, EAP_SIM_K_ENCR_LEN);
wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_aut",
k_aut, EAP_SIM_K_ENCR_LEN);
wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MSK",
msk, MSK_LEN);
wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: Ext. MSK",
msk + MSK_LEN, EMSK_LEN);
wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: keying material",
msk, EAP_SIM_KEYING_DATA_LEN);
msk, EAP_SIM_KEYING_DATA_LEN);
}
void eap_sim_derive_keys_reauth(unsigned int _counter,
void eap_sim_derive_keys_reauth(u16 _counter,
const u8 *identity, size_t identity_len,
const u8 *nonce_s, const u8 *mk, u8 *msk)
{
@ -119,8 +111,7 @@ void eap_sim_derive_keys_reauth(unsigned int _counter,
addr[3] = mk;
len[3] = EAP_SIM_MK_LEN;
counter[0] = _counter >> 8;
counter[1] = _counter & 0xff;
WPA_PUT_BE16(counter, _counter);
wpa_printf(MSG_DEBUG, "EAP-SIM: Deriving keying data from reauth");
wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity",
@ -135,34 +126,37 @@ void eap_sim_derive_keys_reauth(unsigned int _counter,
wpa_hexdump(MSG_DEBUG, "EAP-SIM: XKEY'", xkey, SHA1_MAC_LEN);
eap_sim_prf(xkey, msk, EAP_SIM_KEYING_DATA_LEN);
wpa_hexdump(MSG_DEBUG, "EAP-SIM: MSK", msk, MSK_LEN);
wpa_hexdump(MSG_DEBUG, "EAP-SIM: Ext. MSK", msk + MSK_LEN, EMSK_LEN);
wpa_hexdump(MSG_DEBUG, "EAP-SIM: keying material",
msk, EAP_SIM_KEYING_DATA_LEN);
}
int eap_sim_verify_mac(const u8 *k_aut, u8 *req, size_t req_len, u8 *mac,
u8 *extra, size_t extra_len)
int eap_sim_verify_mac(const u8 *k_aut, const u8 *req, size_t req_len,
const u8 *mac, const u8 *extra, size_t extra_len)
{
unsigned char hmac[SHA1_MAC_LEN];
const u8 *addr[2];
size_t len[2];
u8 rx_mac[EAP_SIM_MAC_LEN];
u8 *tmp;
if (mac == NULL)
if (mac == NULL || req_len < EAP_SIM_MAC_LEN || mac < req ||
mac > req + req_len - EAP_SIM_MAC_LEN)
return -1;
addr[0] = req;
tmp = malloc(req_len);
if (tmp == NULL)
return -1;
addr[0] = tmp;
len[0] = req_len;
addr[1] = extra;
len[1] = extra_len;
/* HMAC-SHA1-128 */
memcpy(rx_mac, mac, EAP_SIM_MAC_LEN);
memset(mac, 0, EAP_SIM_MAC_LEN);
memcpy(tmp, req, req_len);
memset(tmp + (mac - req), 0, EAP_SIM_MAC_LEN);
hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac);
memcpy(mac, rx_mac, EAP_SIM_MAC_LEN);
free(tmp);
return (memcmp(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1;
}
@ -187,10 +181,10 @@ void eap_sim_add_mac(const u8 *k_aut, u8 *msg, size_t msg_len, u8 *mac,
}
int eap_sim_parse_attr(u8 *start, u8 *end, struct eap_sim_attrs *attr, int aka,
int encr)
int eap_sim_parse_attr(const u8 *start, const u8 *end,
struct eap_sim_attrs *attr, int aka, int encr)
{
u8 *pos = start, *apos;
const u8 *pos = start, *apos;
size_t alen, plen;
int list_len, i;
@ -473,25 +467,35 @@ int eap_sim_parse_attr(u8 *start, u8 *end, struct eap_sim_attrs *attr, int aka,
}
int eap_sim_parse_encr(const u8 *k_encr, u8 *encr_data, size_t encr_data_len,
const u8 *iv, struct eap_sim_attrs *attr, int aka)
u8 * eap_sim_parse_encr(const u8 *k_encr, const u8 *encr_data,
size_t encr_data_len, const u8 *iv,
struct eap_sim_attrs *attr, int aka)
{
u8 *decrypted;
if (!iv) {
wpa_printf(MSG_INFO, "EAP-SIM: Encrypted data, but no IV");
return -1;
return NULL;
}
aes_128_cbc_decrypt(k_encr, iv, encr_data, encr_data_len);
wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Decrypted AT_ENCR_DATA",
encr_data, encr_data_len);
if (eap_sim_parse_attr(encr_data, encr_data + encr_data_len, attr,
decrypted = malloc(encr_data_len);
if (decrypted == NULL)
return NULL;
memcpy(decrypted, encr_data, encr_data_len);
aes_128_cbc_decrypt(k_encr, iv, decrypted, encr_data_len);
wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Decrypted AT_ENCR_DATA",
decrypted, encr_data_len);
if (eap_sim_parse_attr(decrypted, decrypted + encr_data_len, attr,
aka, 1)) {
wpa_printf(MSG_INFO, "EAP-SIM: (encr) Failed to parse "
"decrypted AT_ENCR_DATA");
return -1;
free(decrypted);
return NULL;
}
return 0;
return decrypted;
}
@ -628,8 +632,8 @@ u8 * eap_sim_msg_add(struct eap_sim_msg *msg, u8 attr, u16 value,
start = pos = msg->buf + msg->used;
*pos++ = attr;
*pos++ = attr_len / 4;
*pos++ = value >> 8;
*pos++ = value & 0xff;
WPA_PUT_BE16(pos, value);
pos += 2;
if (data)
memcpy(pos, data, len);
if (pad_len) {
@ -709,7 +713,9 @@ int eap_sim_msg_add_encr_end(struct eap_sim_msg *msg, u8 *k_encr, int attr_pad)
void eap_sim_report_notification(void *msg_ctx, int notification, int aka)
{
#ifndef CONFIG_NO_STDOUT_DEBUG
const char *type = aka ? "AKA" : "SIM";
#endif /* CONFIG_NO_STDOUT_DEBUG */
switch (notification) {
case EAP_SIM_GENERAL_FAILURE_AFTER_AUTH:

View file

@ -1,3 +1,17 @@
/*
* WPA Supplicant / EAP-SIM/AKA shared routines
* Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef EAP_SIM_COMMON_H
#define EAP_SIM_COMMON_H
@ -16,11 +30,11 @@
#define AKA_AUTN_LEN 16
void eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk);
void eap_sim_derive_keys_reauth(unsigned int _counter,
void eap_sim_derive_keys_reauth(u16 _counter,
const u8 *identity, size_t identity_len,
const u8 *nonce_s, const u8 *mk, u8 *msk);
int eap_sim_verify_mac(const u8 *k_aut, u8 *req, size_t req_len, u8 *mac,
u8 *extra, size_t extra_len);
int eap_sim_verify_mac(const u8 *k_aut, const u8 *req, size_t req_len,
const u8 *mac, const u8 *extra, size_t extra_len);
void eap_sim_add_mac(const u8 *k_aut, u8 *msg, size_t msg_len, u8 *mac,
const u8 *extra, size_t extra_len);
@ -65,19 +79,20 @@ enum eap_sim_id_req {
struct eap_sim_attrs {
u8 *rand, *autn, *mac, *iv, *encr_data, *version_list, *nonce_s;
u8 *next_pseudonym, *next_reauth_id;
u8 *nonce_mt, *identity;
const u8 *rand, *autn, *mac, *iv, *encr_data, *version_list, *nonce_s;
const u8 *next_pseudonym, *next_reauth_id;
const u8 *nonce_mt, *identity;
size_t num_chal, version_list_len, encr_data_len;
size_t next_pseudonym_len, next_reauth_id_len, identity_len;
enum eap_sim_id_req id_req;
int notification, counter, selected_version, client_error_code;
};
int eap_sim_parse_attr(u8 *start, u8 *end, struct eap_sim_attrs *attr,
int aka, int encr);
int eap_sim_parse_encr(const u8 *k_encr, u8 *encr_data, size_t encr_data_len,
const u8 *iv, struct eap_sim_attrs *attr, int aka);
int eap_sim_parse_attr(const u8 *start, const u8 *end,
struct eap_sim_attrs *attr, int aka, int encr);
u8 * eap_sim_parse_encr(const u8 *k_encr, const u8 *encr_data,
size_t encr_data_len, const u8 *iv,
struct eap_sim_attrs *attr, int aka);
struct eap_sim_msg;

View file

@ -35,48 +35,50 @@ F) failed
-) server did not support
?) not tested
hostapd --------------------------------------------------------.
Cisco Aironet 1200 AP (local RADIUS server) ----------------. |
Corriente Elektron -------------------------------------. | |
Lucent NavisRadiator -------------------------------. | | |
Interlink RAD-Series ---------------------------. | | | |
Radiator -----------------------------------. | | | | |
Meetinghouse Aegis ---------------------. | | | | | |
Funk Steel-Belted ------------------. | | | | | | |
Funk Odyssey -------------------. | | | | | | | |
Microsoft IAS --------------. | | | | | | | | |
FreeRADIUS -------------. | | | | | | | | | |
| | | | | | | | | | |
Cisco ACS ----------------------------------------------------------.
hostapd --------------------------------------------------------. |
Cisco Aironet 1200 AP (local RADIUS server) ----------------. | |
Corriente Elektron -------------------------------------. | | |
Lucent NavisRadius ---------------------------------. | | | |
Interlink RAD-Series ---------------------------. | | | | |
Radiator -----------------------------------. | | | | | |
Meetinghouse Aegis ---------------------. | | | | | | |
Funk Steel-Belted ------------------. | | | | | | | |
Funk Odyssey -------------------. | | | | | | | | |
Microsoft IAS --------------. | | | | | | | | | |
FreeRADIUS -------------. | | | | | | | | | | |
| | | | | | | | | | | |
EAP-MD5 + - - + + + + + - - +
EAP-GTC + - - ? + + + + - - +
EAP-OTP - - - - - + - - - - -
EAP-MSCHAPv2 + - - + + + + + - - +
EAP-TLS + + + + + + + + - - +
EAP-PEAPv0/MSCHAPv2 + + + + + + + + + - +
EAP-PEAPv0/GTC + - + - + + + + - - +
EAP-PEAPv0/OTP - - - - - + - - - - -
EAP-PEAPv0/MD5 + - - + + + + + - - +
EAP-PEAPv0/TLS - + - + + + F + - - -
EAP-PEAPv1/MSCHAPv2 - - + + + +1 + +5 +8 - +
EAP-PEAPv1/GTC - - + + + +1 + +5 - - +
EAP-PEAPv1/OTP - - - - - +1 - - - - -
EAP-PEAPv1/MD5 - - - + + +1 + +5 - - +
EAP-PEAPv1/TLS - - - + + +1 F +5 - - -
EAP-TTLS/CHAP + - +2 + + + + + + - +
EAP-TTLS/MSCHAP + - + + + + + + + - +
EAP-TTLS/MSCHAPv2 + - + + + + + + + - +
EAP-TTLS/PAP + - + + + + + + + - +
EAP-TTLS/EAP-MD5 + - +2 + + + + + - - +
EAP-TTLS/EAP-GTC + - +2 ? + + + + - - +
EAP-TTLS/EAP-OTP - - - - - + - - - - -
EAP-TTLS/EAP-MSCHAPv2 + - +2 + + + + + + - +
EAP-TTLS/EAP-TLS - - +2 + F + + + - - -
EAP-SIM +3 - - ? - + - ? - - +
EAP-AKA - - - - - + - - - - -
EAP-PSK +7 - - - - - - - - - -
EAP-FAST - - - - - - - - - + -
LEAP + - + + + + F +6 - + -
EAP-MD5 + - - + + + + + - - + +
EAP-GTC + - - ? + + + + - - + -
EAP-OTP - - - - - + - - - - - -
EAP-MSCHAPv2 + - - + + + + + - - + -
EAP-TLS + + + + + + + + - - + +
EAP-PEAPv0/MSCHAPv2 + + + + + + + + + - + +
EAP-PEAPv0/GTC + - + - + + + + - - + +
EAP-PEAPv0/OTP - - - - - + - - - - - -
EAP-PEAPv0/MD5 + - - + + + + + - - + -
EAP-PEAPv0/TLS - + - + + + F + - - - -
EAP-PEAPv1/MSCHAPv2 - - + + + +1 + +5 +8 - + +
EAP-PEAPv1/GTC - - + + + +1 + +5 - - + +
EAP-PEAPv1/OTP - - - - - +1 - - - - - -
EAP-PEAPv1/MD5 - - - + + +1 + +5 - - + -
EAP-PEAPv1/TLS - - - + + +1 F +5 - - - -
EAP-TTLS/CHAP + - +2 + + + + + + - + -
EAP-TTLS/MSCHAP + - + + + + + + + - + -
EAP-TTLS/MSCHAPv2 + - + + + + + + + - + -
EAP-TTLS/PAP + - + + + + + + + - + -
EAP-TTLS/EAP-MD5 + - +2 + + + + + - - + -
EAP-TTLS/EAP-GTC + - +2 ? + + + + - - + -
EAP-TTLS/EAP-OTP - - - - - + - - - - - -
EAP-TTLS/EAP-MSCHAPv2 + - +2 + + + + + + - + -
EAP-TTLS/EAP-TLS - - +2 + F + + + - - - -
EAP-SIM +3 - - ? - + - ? - - + -
EAP-AKA - - - - - + - - - - - -
EAP-PSK +7 - - - - - - - - - + -
EAP-PAX - - - - - - - - - - + -
EAP-FAST - - - - - - - - - + - +
LEAP + - + + + + F +6 - + - +
1) PEAPv1 required new label, "client PEAP encryption" instead of "client EAP
encryption", during key derivation (requires phase1="peaplabel=1" in the
@ -309,7 +311,13 @@ hostapd v0.3.3
- EAP-TTLS / EAP-GTC
- EAP-TTLS / EAP-MSCHAPv2
- EAP-SIM
- EAP-PAX
Cisco Secure ACS 3.3(1) for Windows Server
- PEAPv1/GTC worked, but PEAPv0/GTC failed in the end after password was
sent successfully; ACS is replying with empty PEAP packet (TLS ACK);
wpa_supplicant tries to decrypt this.. Replying with TLS ACK and and
marking the connection completed was enough to make this work.
PEAPv1:

View file

@ -38,8 +38,8 @@ static void * eap_tls_init(struct eap_sm *sm)
struct eap_tls_data *data;
struct wpa_ssid *config = eap_get_config(sm);
if (config == NULL ||
(sm->init_phase2 ? config->private_key2 : config->private_key)
== NULL) {
((sm->init_phase2 ? config->private_key2 : config->private_key)
== NULL && config->engine == 0)) {
wpa_printf(MSG_INFO, "EAP-TLS: Private key not configured");
return NULL;
}
@ -52,6 +52,18 @@ static void * eap_tls_init(struct eap_sm *sm)
if (eap_tls_ssl_init(sm, &data->ssl, config)) {
wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
eap_tls_deinit(sm, data);
if (config->engine) {
wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting Smartcard "
"PIN");
eap_sm_request_pin(sm, config);
sm->ignore = TRUE;
} else if (config->private_key && !config->private_key_passwd)
{
wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting private "
"key passphrase");
eap_sm_request_passphrase(sm, config);
sm->ignore = TRUE;
}
return NULL;
}
@ -72,61 +84,23 @@ static void eap_tls_deinit(struct eap_sm *sm, void *priv)
static u8 * eap_tls_process(struct eap_sm *sm, void *priv,
struct eap_method_ret *ret,
u8 *reqData, size_t reqDataLen,
const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
struct eap_hdr *req;
int left, res;
unsigned int tls_msg_len;
u8 flags, *pos, *resp, id;
struct wpa_ssid *config = eap_get_config(sm);
const struct eap_hdr *req;
size_t left;
int res;
u8 flags, *resp, id;
const u8 *pos;
struct eap_tls_data *data = priv;
if (tls_get_errors(sm->ssl_ctx)) {
wpa_printf(MSG_INFO, "EAP-TLS: TLS errors detected");
ret->ignore = TRUE;
pos = eap_tls_process_init(sm, &data->ssl, EAP_TYPE_TLS, ret,
reqData, reqDataLen, &left, &flags);
if (pos == NULL)
return NULL;
}
req = (struct eap_hdr *) reqData;
pos = (u8 *) (req + 1);
if (reqDataLen < sizeof(*req) + 2 || *pos != EAP_TYPE_TLS) {
wpa_printf(MSG_INFO, "EAP-TLS: Invalid frame");
ret->ignore = TRUE;
return NULL;
}
req = (const struct eap_hdr *) reqData;
id = req->identifier;
pos++;
flags = *pos++;
left = be_to_host16(req->length) - sizeof(struct eap_hdr) - 2;
wpa_printf(MSG_DEBUG, "EAP-TLS: Received packet(len=%lu) - "
"Flags 0x%02x", (unsigned long) reqDataLen, flags);
if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
if (left < 4) {
wpa_printf(MSG_INFO, "EAP-TLS: Short frame with TLS "
"length");
ret->ignore = TRUE;
return NULL;
}
tls_msg_len = (pos[0] << 24) | (pos[1] << 16) | (pos[2] << 8) |
pos[3];
wpa_printf(MSG_DEBUG, "EAP-TLS: TLS Message Length: %d",
tls_msg_len);
if (data->ssl.tls_in_left == 0) {
data->ssl.tls_in_total = tls_msg_len;
data->ssl.tls_in_left = tls_msg_len;
free(data->ssl.tls_in);
data->ssl.tls_in = NULL;
data->ssl.tls_in_len = 0;
}
pos += 4;
left -= 4;
}
ret->ignore = FALSE;
ret->methodState = METHOD_CONT;
ret->decision = DECISION_COND_SUCC;
ret->allowNotifications = TRUE;
if (flags & EAP_TLS_FLAGS_START) {
wpa_printf(MSG_DEBUG, "EAP-TLS: Start");
@ -142,6 +116,11 @@ static u8 * eap_tls_process(struct eap_sm *sm, void *priv,
wpa_printf(MSG_DEBUG, "EAP-TLS: TLS processing failed");
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
if (resp) {
/* This is likely an alert message, so send it instead
* of just ACKing the error. */
return resp;
}
return eap_tls_build_ack(&data->ssl, respDataLen, id,
EAP_TYPE_TLS, 0);
}
@ -166,6 +145,16 @@ static u8 * eap_tls_process(struct eap_sm *sm, void *priv,
return eap_tls_build_ack(&data->ssl, respDataLen, id,
EAP_TYPE_TLS, 0);
}
if (res == -1) {
/* The TLS handshake failed. So better forget the old PIN.
* It may be wrong, we can't be sure but trying the wrong one
* again might block it on the card - so better ask the user
* again */
free(config->pin);
config->pin = NULL;
}
return resp;
}

View file

@ -24,39 +24,82 @@
#include "md5.h"
#include "sha1.h"
#include "tls.h"
#include "config.h"
static int eap_tls_check_blob(struct eap_sm *sm, const char **name,
const u8 **data, size_t *data_len)
{
const struct wpa_config_blob *blob;
if (*name == NULL || strncmp(*name, "blob://", 7) != 0)
return 0;
blob = eap_get_config_blob(sm, *name + 7);
if (blob == NULL) {
wpa_printf(MSG_ERROR, "%s: Named configuration blob '%s' not "
"found", __func__, *name + 7);
return -1;
}
*name = NULL;
*data = blob->data;
*data_len = blob->len;
return 0;
}
int eap_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
struct wpa_ssid *config)
{
int ret = -1;
char *ca_cert, *client_cert, *private_key, *private_key_passwd,
*dh_file, *subject_match;
int ret = -1, res;
struct tls_connection_params params;
data->eap = sm;
data->phase2 = sm->init_phase2;
memset(&params, 0, sizeof(params));
params.engine = config->engine;
if (config == NULL) {
ca_cert = NULL;
client_cert = NULL;
private_key = NULL;
private_key_passwd = NULL;
dh_file = NULL;
subject_match = NULL;
} else if (data->phase2) {
ca_cert = (char *) config->ca_cert2;
client_cert = (char *) config->client_cert2;
private_key = (char *) config->private_key2;
private_key_passwd = (char *) config->private_key2_passwd;
dh_file = (char *) config->dh_file2;
subject_match = (char *) config->subject_match2;
params.ca_cert = (char *) config->ca_cert2;
params.ca_path = (char *) config->ca_path2;
params.client_cert = (char *) config->client_cert2;
params.private_key = (char *) config->private_key2;
params.private_key_passwd =
(char *) config->private_key2_passwd;
params.dh_file = (char *) config->dh_file2;
params.subject_match = (char *) config->subject_match2;
params.altsubject_match = (char *) config->altsubject_match2;
} else {
ca_cert = (char *) config->ca_cert;
client_cert = (char *) config->client_cert;
private_key = (char *) config->private_key;
private_key_passwd = (char *) config->private_key_passwd;
dh_file = (char *) config->dh_file;
subject_match = (char *) config->subject_match;
params.ca_cert = (char *) config->ca_cert;
params.ca_path = (char *) config->ca_path;
params.client_cert = (char *) config->client_cert;
params.private_key = (char *) config->private_key;
params.private_key_passwd =
(char *) config->private_key_passwd;
params.dh_file = (char *) config->dh_file;
params.subject_match = (char *) config->subject_match;
params.altsubject_match = (char *) config->altsubject_match;
params.engine_id = config->engine_id;
params.pin = config->pin;
params.key_id = config->key_id;
}
if (eap_tls_check_blob(sm, &params.ca_cert, &params.ca_cert_blob,
&params.ca_cert_blob_len) ||
eap_tls_check_blob(sm, &params.client_cert,
&params.client_cert_blob,
&params.client_cert_blob_len) ||
eap_tls_check_blob(sm, &params.private_key,
&params.private_key_blob,
&params.private_key_blob_len) ||
eap_tls_check_blob(sm, &params.dh_file, &params.dh_blob,
&params.dh_blob_len)) {
wpa_printf(MSG_INFO, "SSL: Failed to get configuration blobs");
goto done;
}
data->conn = tls_connection_init(sm->ssl_ctx);
if (data->conn == NULL) {
wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
@ -64,29 +107,25 @@ int eap_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
goto done;
}
if (tls_connection_ca_cert(sm->ssl_ctx, data->conn, ca_cert,
subject_match)) {
wpa_printf(MSG_INFO, "TLS: Failed to load root certificate "
"'%s'", ca_cert);
res = tls_connection_set_params(sm->ssl_ctx, data->conn, &params);
if (res == TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED) {
/* At this point with the pkcs11 engine the PIN might be wrong.
* We reset the PIN in the configuration to be sure to not use
* it again and the calling function must request a new one */
free(config->pin);
config->pin = NULL;
} else if (res == TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED) {
wpa_printf(MSG_INFO,"TLS: Failed to load private key");
/* We don't know exactly but maybe the PIN was wrong,
* so ask for a new one. */
free(config->pin);
config->pin = NULL;
eap_sm_request_pin(sm, config);
sm->ignore = TRUE;
goto done;
}
if (tls_connection_client_cert(sm->ssl_ctx, data->conn, client_cert)) {
wpa_printf(MSG_INFO, "TLS: Failed to load client certificate "
"'%s'", client_cert);
goto done;
}
if (tls_connection_private_key(sm->ssl_ctx, data->conn, private_key,
private_key_passwd)) {
wpa_printf(MSG_INFO, "TLS: Failed to load private key '%s'",
private_key);
goto done;
}
if (dh_file && tls_connection_dh(sm->ssl_ctx, data->conn, dh_file)) {
wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'",
dh_file);
} else if (res) {
wpa_printf(MSG_INFO, "TLS: Failed to set TLS connection "
"parameters");
goto done;
}
@ -126,93 +165,131 @@ u8 * eap_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
char *label, size_t len)
{
struct tls_keys keys;
u8 *random;
u8 *rnd;
u8 *out;
if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
return NULL;
if (keys.eap_tls_prf && strcmp(label, "client EAP encryption") == 0) {
if (len > keys.eap_tls_prf_len)
return NULL;
out = malloc(len);
if (out == NULL)
return NULL;
memcpy(out, keys.eap_tls_prf, len);
return out;
}
if (keys.client_random == NULL || keys.server_random == NULL ||
keys.master_key == NULL)
return NULL;
out = malloc(len);
random = malloc(keys.client_random_len + keys.server_random_len);
if (out == NULL || random == NULL) {
rnd = malloc(keys.client_random_len + keys.server_random_len);
if (out == NULL || rnd == NULL) {
free(out);
free(random);
free(rnd);
return NULL;
}
memcpy(random, keys.client_random, keys.client_random_len);
memcpy(random + keys.client_random_len, keys.server_random,
memcpy(rnd, keys.client_random, keys.client_random_len);
memcpy(rnd + keys.client_random_len, keys.server_random,
keys.server_random_len);
if (tls_prf(keys.master_key, keys.master_key_len,
label, random, keys.client_random_len +
label, rnd, keys.client_random_len +
keys.server_random_len, out, len)) {
free(random);
free(rnd);
free(out);
return NULL;
}
free(random);
free(rnd);
return out;
}
int eap_tls_data_reassemble(struct eap_sm *sm, struct eap_ssl_data *data,
u8 **in_data, size_t *in_len)
/**
* eap_tls_data_reassemble - Reassemble TLS data
* @sm: Pointer to EAP state machine allocated with eap_sm_init()
* @data: Data for TLS processing
* @in_data: Next incoming TLS segment
* @in_len: Length of in_data
* @out_len: Variable for returning output data length
* @need_more_input: Variable for returning whether more input data is needed
* to reassemble this TLS packet
* Returns: Pointer to output data or %NULL on error
*
* This function reassembles TLS fragments.
*/
const u8 * eap_tls_data_reassemble(
struct eap_sm *sm, struct eap_ssl_data *data, const u8 *in_data,
size_t in_len, size_t *out_len, int *need_more_input)
{
u8 *buf;
if (data->tls_in_left > *in_len || data->tls_in) {
if (data->tls_in_len + *in_len == 0) {
*need_more_input = 0;
if (data->tls_in_left > in_len || data->tls_in) {
if (data->tls_in_len + in_len == 0) {
free(data->tls_in);
data->tls_in = NULL;
data->tls_in_len = 0;
wpa_printf(MSG_WARNING, "SSL: Invalid reassembly "
"state: tls_in_left=%d tls_in_len=%d "
"*in_len=%d",
data->tls_in_left, data->tls_in_len,
*in_len);
return -1;
"state: tls_in_left=%lu tls_in_len=%lu "
"in_len=%lu",
(unsigned long) data->tls_in_left,
(unsigned long) data->tls_in_len,
(unsigned long) in_len);
return NULL;
}
buf = realloc(data->tls_in, data->tls_in_len + *in_len);
buf = realloc(data->tls_in, data->tls_in_len + in_len);
if (buf == NULL) {
free(data->tls_in);
data->tls_in = NULL;
data->tls_in_len = 0;
wpa_printf(MSG_INFO, "SSL: Could not allocate memory "
"for TLS data");
return -1;
return NULL;
}
memcpy(buf + data->tls_in_len, *in_data, *in_len);
memcpy(buf + data->tls_in_len, in_data, in_len);
data->tls_in = buf;
data->tls_in_len += *in_len;
if (*in_len > data->tls_in_left) {
data->tls_in_len += in_len;
if (in_len > data->tls_in_left) {
wpa_printf(MSG_INFO, "SSL: more data than TLS message "
"length indicated");
data->tls_in_left = 0;
return -1;
return NULL;
}
data->tls_in_left -= *in_len;
data->tls_in_left -= in_len;
if (data->tls_in_left > 0) {
wpa_printf(MSG_DEBUG, "SSL: Need %lu bytes more input "
"data", (unsigned long) data->tls_in_left);
return 1;
*need_more_input = 1;
return NULL;
}
*in_data = data->tls_in;
*in_len = data->tls_in_len;
} else
} else {
data->tls_in_left = 0;
data->tls_in = malloc(in_len);
if (data->tls_in == NULL)
return NULL;
memcpy(data->tls_in, in_data, in_len);
data->tls_in_len = in_len;
}
return 0;
*out_len = data->tls_in_len;
return data->tls_in;
}
int eap_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
int eap_type, int peap_version,
u8 id, u8 *in_data, size_t in_len,
u8 id, const u8 *in_data, size_t in_len,
u8 **out_data, size_t *out_len)
{
size_t len;
u8 *pos, *flags;
struct eap_hdr *resp;
int ret = 0;
WPA_ASSERT(data->tls_out_len == 0 || in_len == 0);
*out_len = 0;
@ -220,9 +297,15 @@ int eap_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
if (data->tls_out_len == 0) {
/* No more data to send out - expect to receive more data from
* the AS. */
int res = eap_tls_data_reassemble(sm, data, &in_data, &in_len);
if (res < 0 || res == 1)
return res;
const u8 *msg;
size_t msg_len;
int need_more_input;
msg = eap_tls_data_reassemble(sm, data, in_data, in_len,
&msg_len, &need_more_input);
if (msg == NULL)
return need_more_input ? 1 : -1;
/* Full TLS message reassembled - continue handshake processing
*/
if (data->tls_out) {
@ -235,7 +318,7 @@ int eap_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
}
data->tls_out = tls_connection_handshake(sm->ssl_ctx,
data->conn,
in_data, in_len,
msg, msg_len,
&data->tls_out_len);
/* Clear reassembled input data (if the buffer was needed). */
@ -248,6 +331,13 @@ int eap_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
data->tls_out_len = 0;
return -1;
}
if (tls_connection_get_failed(sm->ssl_ctx, data->conn)) {
wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to "
"report error");
ret = -1;
/* TODO: clean pin if engine used? */
}
if (data->tls_out_len == 0) {
/* TLS negotiation should now be complete since all other cases
* needing more that should have been catched above based on
@ -303,7 +393,7 @@ int eap_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
data->tls_out = NULL;
}
return 0;
return ret;
}
@ -330,6 +420,13 @@ u8 * eap_tls_build_ack(struct eap_ssl_data *data, size_t *respDataLen, u8 id,
int eap_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data)
{
free(data->tls_in);
data->tls_in = NULL;
data->tls_in_len = data->tls_in_left = data->tls_in_total = 0;
free(data->tls_out);
data->tls_out = NULL;
data->tls_out_len = data->tls_out_pos = 0;
return tls_connection_shutdown(sm->ssl_ctx, data->conn);
}
@ -347,3 +444,61 @@ int eap_tls_status(struct eap_sm *sm, struct eap_ssl_data *data, char *buf,
return len;
}
const u8 * eap_tls_process_init(struct eap_sm *sm, struct eap_ssl_data *data,
EapType eap_type, struct eap_method_ret *ret,
const u8 *reqData, size_t reqDataLen,
size_t *len, u8 *flags)
{
const struct eap_hdr *req;
const u8 *pos;
size_t left;
unsigned int tls_msg_len;
if (tls_get_errors(sm->ssl_ctx)) {
wpa_printf(MSG_INFO, "SSL: TLS errors detected");
ret->ignore = TRUE;
return NULL;
}
pos = eap_hdr_validate(eap_type, reqData, reqDataLen, &left);
if (pos == NULL) {
ret->ignore = TRUE;
return NULL;
}
req = (const struct eap_hdr *) reqData;
*flags = *pos++;
left--;
wpa_printf(MSG_DEBUG, "SSL: Received packet(len=%lu) - "
"Flags 0x%02x", (unsigned long) reqDataLen, *flags);
if (*flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
if (left < 4) {
wpa_printf(MSG_INFO, "SSL: Short frame with TLS "
"length");
ret->ignore = TRUE;
return NULL;
}
tls_msg_len = (pos[0] << 24) | (pos[1] << 16) | (pos[2] << 8) |
pos[3];
wpa_printf(MSG_DEBUG, "SSL: TLS Message Length: %d",
tls_msg_len);
if (data->tls_in_left == 0) {
data->tls_in_total = tls_msg_len;
data->tls_in_left = tls_msg_len;
free(data->tls_in);
data->tls_in = NULL;
data->tls_in_len = 0;
}
pos += 4;
left -= 4;
}
ret->ignore = FALSE;
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
ret->allowNotifications = TRUE;
*len = (size_t) left;
return pos;
}

View file

@ -1,3 +1,17 @@
/*
* WPA Supplicant / EAP-TLS/PEAP/TTLS/FAST common functions
* Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef EAP_TLS_COMMON_H
#define EAP_TLS_COMMON_H
@ -36,16 +50,21 @@ int eap_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
void eap_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data);
u8 * eap_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
char *label, size_t len);
int eap_tls_data_reassemble(struct eap_sm *sm, struct eap_ssl_data *data,
u8 **in_data, size_t *in_len);
const u8 * eap_tls_data_reassemble(
struct eap_sm *sm, struct eap_ssl_data *data, const u8 *in_data,
size_t in_len, size_t *out_len, int *need_more_input);
int eap_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
int eap_type, int peap_version,
u8 id, u8 *in_data, size_t in_len,
u8 id, const u8 *in_data, size_t in_len,
u8 **out_data, size_t *out_len);
u8 * eap_tls_build_ack(struct eap_ssl_data *data, size_t *respDataLen, u8 id,
int eap_type, int peap_version);
int eap_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data);
int eap_tls_status(struct eap_sm *sm, struct eap_ssl_data *data, char *buf,
size_t buflen, int verbose);
const u8 * eap_tls_process_init(struct eap_sm *sm, struct eap_ssl_data *data,
EapType eap_type, struct eap_method_ret *ret,
const u8 *reqData, size_t reqDataLen,
size_t *len, u8 *flags);
#endif /* EAP_TLS_COMMON_H */

View file

@ -22,7 +22,7 @@
#include "eap_tlv.h"
u8 * eap_tlv_build_nak(int id, int nak_type, size_t *resp_len)
u8 * eap_tlv_build_nak(int id, u16 nak_type, size_t *resp_len)
{
struct eap_hdr *hdr;
u8 *pos;
@ -48,14 +48,13 @@ u8 * eap_tlv_build_nak(int id, int nak_type, size_t *resp_len)
*pos++ = 0;
*pos++ = 0;
/* NAK-Type */
*pos++ = nak_type >> 8;
*pos++ = nak_type & 0xff;
WPA_PUT_BE16(pos, nak_type);
return (u8 *) hdr;
}
u8 * eap_tlv_build_result(int id, int status, size_t *resp_len)
u8 * eap_tlv_build_result(int id, u16 status, size_t *resp_len)
{
struct eap_hdr *hdr;
u8 *pos;
@ -76,33 +75,32 @@ u8 * eap_tlv_build_result(int id, int status, size_t *resp_len)
*pos++ = 0;
*pos++ = 2;
/* Status */
*pos++ = status >> 8;
*pos++ = status & 0xff;
WPA_PUT_BE16(pos, status);
return (u8 *) hdr;
}
int eap_tlv_process(struct eap_sm *sm, struct eap_method_ret *ret,
struct eap_hdr *hdr, u8 **resp, size_t *resp_len)
const struct eap_hdr *hdr, u8 **resp, size_t *resp_len)
{
size_t left;
u8 *pos;
u8 *result_tlv = NULL;
const u8 *pos;
const u8 *result_tlv = NULL;
size_t result_tlv_len = 0;
int tlv_type, mandatory, tlv_len;
/* Parse TLVs */
left = be_to_host16(hdr->length) - sizeof(struct eap_hdr) - 1;
pos = (u8 *) (hdr + 1);
pos = (const u8 *) (hdr + 1);
pos++;
wpa_hexdump(MSG_DEBUG, "EAP-TLV: Received TLVs", pos, left);
while (left >= 4) {
mandatory = !!(pos[0] & 0x80);
tlv_type = pos[0] & 0x3f;
tlv_type = (tlv_type << 8) | pos[1];
tlv_len = ((int) pos[2] << 8) | pos[3];
pos += 4;
tlv_type = WPA_GET_BE16(pos) & 0x3fff;
pos += 2;
tlv_len = WPA_GET_BE16(pos);
pos += 2;
left -= 4;
if (tlv_len > left) {
wpa_printf(MSG_DEBUG, "EAP-TLV: TLV underrun "
@ -150,7 +148,7 @@ int eap_tlv_process(struct eap_sm *sm, struct eap_method_ret *ret,
(unsigned long) result_tlv_len);
return -1;
}
status = ((int) result_tlv[0] << 8) | result_tlv[1];
status = WPA_GET_BE16(result_tlv);
if (status == EAP_TLV_RESULT_SUCCESS) {
wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Success "
"- EAP-TLV/Phase2 Completed");

View file

@ -1,3 +1,17 @@
/*
* WPA Supplicant / EAP-TLV (draft-josefsson-pppext-eap-tls-eap-07.txt)
* Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef EAP_TLV_H
#define EAP_TLV_H
@ -65,9 +79,9 @@ struct eap_tlv_pac_ack_tlv {
#define EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE 1
u8 * eap_tlv_build_nak(int id, int nak_type, size_t *resp_len);
u8 * eap_tlv_build_result(int id, int status, size_t *resp_len);
u8 * eap_tlv_build_nak(int id, u16 nak_type, size_t *resp_len);
u8 * eap_tlv_build_result(int id, u16 status, size_t *resp_len);
int eap_tlv_process(struct eap_sm *sm, struct eap_method_ret *ret,
struct eap_hdr *hdr, u8 **resp, size_t *resp_len);
const struct eap_hdr *hdr, u8 **resp, size_t *resp_len);
#endif /* EAP_TLV_H */

View file

@ -22,7 +22,7 @@
#include "wpa_supplicant.h"
#include "config_ssid.h"
#include "ms_funcs.h"
#include "md5.h"
#include "crypto.h"
#include "tls.h"
#include "eap_ttls.h"
@ -183,7 +183,7 @@ static void eap_ttls_deinit(struct eap_sm *sm, void *priv)
static int eap_ttls_encrypt(struct eap_sm *sm, struct eap_ttls_data *data,
int id, u8 *plain, size_t plain_len,
int id, const u8 *plain, size_t plain_len,
u8 **out_data, size_t *out_len)
{
int res;
@ -312,7 +312,7 @@ static int eap_ttls_phase2_nak(struct eap_sm *sm,
static int eap_ttls_phase2_request_eap(struct eap_sm *sm,
struct eap_ttls_data *data,
struct eap_method_ret *ret,
struct eap_hdr *req,
const struct eap_hdr *req,
struct eap_hdr *hdr,
u8 **resp, size_t *resp_len)
{
@ -400,7 +400,7 @@ static int eap_ttls_phase2_request_eap(struct eap_sm *sm,
static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
struct eap_ttls_data *data,
struct eap_method_ret *ret,
struct eap_hdr *req,
const struct eap_hdr *req,
struct eap_hdr *hdr,
u8 **resp, size_t *resp_len)
{
@ -506,7 +506,7 @@ static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
static int eap_ttls_phase2_request_mschap(struct eap_sm *sm,
struct eap_ttls_data *data,
struct eap_method_ret *ret,
struct eap_hdr *req,
const struct eap_hdr *req,
struct eap_hdr *hdr,
u8 **resp, size_t *resp_len)
{
@ -576,7 +576,7 @@ static int eap_ttls_phase2_request_mschap(struct eap_sm *sm,
static int eap_ttls_phase2_request_pap(struct eap_sm *sm,
struct eap_ttls_data *data,
struct eap_method_ret *ret,
struct eap_hdr *req,
const struct eap_hdr *req,
struct eap_hdr *hdr,
u8 **resp, size_t *resp_len)
{
@ -624,13 +624,14 @@ static int eap_ttls_phase2_request_pap(struct eap_sm *sm,
static int eap_ttls_phase2_request_chap(struct eap_sm *sm,
struct eap_ttls_data *data,
struct eap_method_ret *ret,
struct eap_hdr *req,
const struct eap_hdr *req,
struct eap_hdr *hdr,
u8 **resp, size_t *resp_len)
{
struct wpa_ssid *config = eap_get_config(sm);
u8 *buf, *pos, *challenge;
MD5_CTX context;
const u8 *addr[3];
size_t len[3];
wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 CHAP Request");
@ -665,11 +666,13 @@ static int eap_ttls_phase2_request_chap(struct eap_sm *sm,
*pos++ = data->ident;
/* MD5(Ident + Password + Challenge) */
MD5Init(&context);
MD5Update(&context, &data->ident, 1);
MD5Update(&context, config->password, config->password_len);
MD5Update(&context, challenge, EAP_TTLS_CHAP_CHALLENGE_LEN);
MD5Final(pos, &context);
addr[0] = &data->ident;
len[0] = 1;
addr[1] = config->password;
len[1] = config->password_len;
addr[2] = challenge;
len[2] = EAP_TTLS_CHAP_CHALLENGE_LEN;
md5_vector(3, addr, len, pos);
wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: CHAP username",
config->identity, config->identity_len);
@ -698,7 +701,7 @@ static int eap_ttls_phase2_request_chap(struct eap_sm *sm,
static int eap_ttls_phase2_request(struct eap_sm *sm,
struct eap_ttls_data *data,
struct eap_method_ret *ret,
struct eap_hdr *req,
const struct eap_hdr *req,
struct eap_hdr *hdr,
u8 **resp, size_t *resp_len)
{
@ -763,12 +766,13 @@ static int eap_ttls_phase2_request(struct eap_sm *sm,
static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data,
struct eap_method_ret *ret, struct eap_hdr *req,
u8 *in_data, size_t in_len,
struct eap_method_ret *ret,
const struct eap_hdr *req,
const u8 *in_data, size_t in_len,
u8 **out_data, size_t *out_len)
{
u8 *in_decrypted = NULL, *pos;
int buf_len, len_decrypted = 0, len, left, retval = 0, res;
int buf_len, len_decrypted = 0, len, left, retval = 0;
struct eap_hdr *hdr = NULL;
u8 *resp = NULL, *mschapv2 = NULL, *eapdata = NULL;
size_t resp_len, eap_len = 0;
@ -776,6 +780,9 @@ static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data,
u8 recv_response[20];
int mschapv2_error = 0;
struct wpa_ssid *config = eap_get_config(sm);
const u8 *msg;
size_t msg_len;
int need_more_input;
wpa_printf(MSG_DEBUG, "EAP-TTLS: received %lu bytes encrypted data for"
" Phase 2", (unsigned long) in_len);
@ -839,11 +846,10 @@ static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data,
goto process_eap;
}
res = eap_tls_data_reassemble(sm, &data->ssl, &in_data, &in_len);
if (res < 0 || res == 1) {
retval = res;
goto done;
}
msg = eap_tls_data_reassemble(sm, &data->ssl, in_data, in_len,
&msg_len, &need_more_input);
if (msg == NULL)
return need_more_input ? 1 : -1;
buf_len = in_len;
if (data->ssl.tls_in_total > buf_len)
@ -860,7 +866,7 @@ static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data,
}
len_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
in_data, in_len,
msg, msg_len,
in_decrypted, buf_len);
free(data->ssl.tls_in);
data->ssl.tls_in = NULL;
@ -1117,7 +1123,8 @@ continue_req:
free(resp);
} else if (config->pending_req_identity ||
config->pending_req_password ||
config->pending_req_otp) {
config->pending_req_otp ||
config->pending_req_new_password) {
free(data->pending_phase2_req);
data->pending_phase2_req = malloc(len_decrypted);
if (data->pending_phase2_req) {
@ -1142,62 +1149,22 @@ done:
static u8 * eap_ttls_process(struct eap_sm *sm, void *priv,
struct eap_method_ret *ret,
u8 *reqData, size_t reqDataLen,
const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
struct eap_hdr *req;
int left, res;
unsigned int tls_msg_len;
u8 flags, *pos, *resp, id;
const struct eap_hdr *req;
size_t left;
int res;
u8 flags, *resp, id;
const u8 *pos;
struct eap_ttls_data *data = priv;
if (tls_get_errors(sm->ssl_ctx)) {
wpa_printf(MSG_INFO, "EAP-TTLS: TLS errors detected");
ret->ignore = TRUE;
pos = eap_tls_process_init(sm, &data->ssl, EAP_TYPE_TTLS, ret,
reqData, reqDataLen, &left, &flags);
if (pos == NULL)
return NULL;
}
req = (struct eap_hdr *) reqData;
pos = (u8 *) (req + 1);
if (reqDataLen < sizeof(*req) + 2 || *pos != EAP_TYPE_TTLS ||
(left = be_to_host16(req->length)) > reqDataLen) {
wpa_printf(MSG_INFO, "EAP-TTLS: Invalid frame");
ret->ignore = TRUE;
return NULL;
}
left -= sizeof(struct eap_hdr);
req = (const struct eap_hdr *) reqData;
id = req->identifier;
pos++;
flags = *pos++;
left -= 2;
wpa_printf(MSG_DEBUG, "EAP-TTLS: Received packet(len=%lu) - "
"Flags 0x%02x", (unsigned long) reqDataLen, flags);
if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
if (left < 4) {
wpa_printf(MSG_INFO, "EAP-TTLS: Short frame with TLS "
"length");
ret->ignore = TRUE;
return NULL;
}
tls_msg_len = (pos[0] << 24) | (pos[1] << 16) | (pos[2] << 8) |
pos[3];
wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS Message Length: %d",
tls_msg_len);
if (data->ssl.tls_in_left == 0) {
data->ssl.tls_in_total = tls_msg_len;
data->ssl.tls_in_left = tls_msg_len;
free(data->ssl.tls_in);
data->ssl.tls_in = NULL;
data->ssl.tls_in_len = 0;
}
pos += 4;
left -= 4;
}
ret->ignore = FALSE;
ret->methodState = METHOD_CONT;
ret->decision = DECISION_FAIL;
ret->allowNotifications = TRUE;
if (flags & EAP_TLS_FLAGS_START) {
wpa_printf(MSG_DEBUG, "EAP-TTLS: Start");

View file

@ -1,3 +1,17 @@
/*
* WPA Supplicant / EAP-TTLS (draft-ietf-pppext-eap-ttls-03.txt)
* Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef EAP_TTLS_H
#define EAP_TTLS_H

View file

@ -20,15 +20,17 @@
#include "eapol_sm.h"
#include "eap.h"
#include "eloop.h"
#include "wpa_supplicant.h"
#include "l2_packet.h"
#include "wpa.h"
#include "md5.h"
#include "rc4.h"
/* IEEE 802.1aa/D6.1 - Supplicant */
/* IEEE 802.1X-2004 - Supplicant - EAPOL state machines */
/**
* struct eapol_sm - Internal data for EAPOL state machines
*/
struct eapol_sm {
/* Timers */
unsigned int authWhile;
@ -118,7 +120,7 @@ struct eapol_sm {
unsigned int dot1xSuppLastEapolFrameVersion;
unsigned char dot1xSuppLastEapolFrameSource[6];
/* Miscellaneous variables (not defined in IEEE 802.1aa/D6.1) */
/* Miscellaneous variables (not defined in IEEE 802.1X-2004) */
Boolean changed;
struct eap_sm *eap;
struct wpa_ssid *config;
@ -141,6 +143,38 @@ struct eapol_sm {
};
#define IEEE8021X_REPLAY_COUNTER_LEN 8
#define IEEE8021X_KEY_SIGN_LEN 16
#define IEEE8021X_KEY_IV_LEN 16
#define IEEE8021X_KEY_INDEX_FLAG 0x80
#define IEEE8021X_KEY_INDEX_MASK 0x03
struct ieee802_1x_eapol_key {
u8 type;
/* Note: key_length is unaligned */
u8 key_length[2];
/* does not repeat within the life of the keying material used to
* encrypt the Key field; 64-bit NTP timestamp MAY be used here */
u8 replay_counter[IEEE8021X_REPLAY_COUNTER_LEN];
u8 key_iv[IEEE8021X_KEY_IV_LEN]; /* cryptographically random number */
u8 key_index; /* key flag in the most significant bit:
* 0 = broadcast (default key),
* 1 = unicast (key mapping key); key index is in the
* 7 least significant bits */
/* HMAC-MD5 message integrity check computed with MS-MPPE-Send-Key as
* the key */
u8 key_signature[IEEE8021X_KEY_SIGN_LEN];
/* followed by key: if packet body length = 44 + key length, then the
* key field (of key_length bytes) contains the key in encrypted form;
* if packet body length = 44, key field is absent and key_length
* represents the number of least significant octets from
* MS-MPPE-Send-Key attribute to be used as the keying material;
* RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */
} __attribute__ ((packed));
static void eapol_sm_txLogoff(struct eapol_sm *sm);
static void eapol_sm_txStart(struct eapol_sm *sm);
static void eapol_sm_processKey(struct eapol_sm *sm);
@ -150,8 +184,6 @@ static void eapol_sm_abortSupp(struct eapol_sm *sm);
static void eapol_sm_abort_cached(struct eapol_sm *sm);
static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx);
static struct eapol_callbacks eapol_cb;
/* Definitions for clarifying state machine implementation */
#define SM_STATE(machine, state) \
@ -182,17 +214,26 @@ static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
{
struct eapol_sm *sm = timeout_ctx;
if (sm->authWhile > 0)
if (sm->authWhile > 0) {
sm->authWhile--;
if (sm->heldWhile > 0)
if (sm->authWhile == 0)
wpa_printf(MSG_DEBUG, "EAPOL: authWhile --> 0");
}
if (sm->heldWhile > 0) {
sm->heldWhile--;
if (sm->startWhen > 0)
if (sm->heldWhile == 0)
wpa_printf(MSG_DEBUG, "EAPOL: heldWhile --> 0");
}
if (sm->startWhen > 0) {
sm->startWhen--;
if (sm->idleWhile > 0)
if (sm->startWhen == 0)
wpa_printf(MSG_DEBUG, "EAPOL: startWhen --> 0");
}
if (sm->idleWhile > 0) {
sm->idleWhile--;
wpa_printf(MSG_MSGDUMP, "EAPOL: Port Timers tick - authWhile=%d "
"heldWhile=%d startWhen=%d idleWhile=%d",
sm->authWhile, sm->heldWhile, sm->startWhen, sm->idleWhile);
if (sm->idleWhile == 0)
wpa_printf(MSG_DEBUG, "EAPOL: idleWhile --> 0");
}
eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx, sm);
eapol_sm_step(sm);
@ -224,11 +265,24 @@ SM_STATE(SUPP_PAE, DISCONNECTED)
SM_STATE(SUPP_PAE, CONNECTING)
{
int send_start = sm->SUPP_PAE_state == SUPP_PAE_CONNECTING;
SM_ENTRY(SUPP_PAE, CONNECTING);
sm->startWhen = sm->startPeriod;
sm->startCount++;
if (send_start) {
sm->startWhen = sm->startPeriod;
sm->startCount++;
} else {
/*
* Do not send EAPOL-Start immediately since in most cases,
* Authenticator is going to start authentication immediately
* after association and an extra EAPOL-Start is just going to
* delay authentication. Use a short timeout to send the first
* EAPOL-Start if Authenticator does not start authentication.
*/
sm->startWhen = 3;
}
sm->eapolEap = FALSE;
eapol_sm_txStart(sm);
if (send_start)
eapol_sm_txStart(sm);
}
@ -532,8 +586,8 @@ SM_STEP(SUPP_BE)
static void eapol_sm_txLogoff(struct eapol_sm *sm)
{
wpa_printf(MSG_DEBUG, "EAPOL: txLogoff");
sm->ctx->eapol_send(sm->ctx->ctx, IEEE802_1X_TYPE_EAPOL_LOGOFF,
(u8 *) "", 0);
sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
IEEE802_1X_TYPE_EAPOL_LOGOFF, (u8 *) "", 0);
sm->dot1xSuppEapolLogoffFramesTx++;
sm->dot1xSuppEapolFramesTx++;
}
@ -542,8 +596,8 @@ static void eapol_sm_txLogoff(struct eapol_sm *sm)
static void eapol_sm_txStart(struct eapol_sm *sm)
{
wpa_printf(MSG_DEBUG, "EAPOL: txStart");
sm->ctx->eapol_send(sm->ctx->ctx, IEEE802_1X_TYPE_EAPOL_START,
(u8 *) "", 0);
sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
IEEE802_1X_TYPE_EAPOL_START, (u8 *) "", 0);
sm->dot1xSuppEapolStartFramesTx++;
sm->dot1xSuppEapolFramesTx++;
}
@ -566,6 +620,7 @@ static void eapol_sm_processKey(struct eapol_sm *sm)
u8 orig_key_sign[IEEE8021X_KEY_SIGN_LEN], datakey[32];
u8 ekey[IEEE8021X_KEY_IV_LEN + IEEE8021X_ENCR_KEY_LEN];
int key_len, res, sign_key_len, encr_key_len;
u16 rx_key_length;
wpa_printf(MSG_DEBUG, "EAPOL: processKey");
if (sm->last_rx_key == NULL)
@ -584,11 +639,13 @@ static void eapol_sm_processKey(struct eapol_sm *sm)
wpa_printf(MSG_WARNING, "EAPOL: Too short EAPOL-Key frame");
return;
}
rx_key_length = WPA_GET_BE16(key->key_length);
wpa_printf(MSG_DEBUG, "EAPOL: RX IEEE 802.1X ver=%d type=%d len=%d "
"EAPOL-Key: type=%d key_length=%d key_index=0x%x",
hdr->version, hdr->type, be_to_host16(hdr->length),
key->type, be_to_host16(key->key_length), key->key_index);
key->type, rx_key_length, key->key_index);
eapol_sm_notify_lower_layer_success(sm);
sign_key_len = IEEE8021X_SIGN_KEY_LEN;
encr_key_len = IEEE8021X_ENCR_KEY_LEN;
res = eapol_sm_get_key(sm, (u8 *) &keydata, sizeof(keydata));
@ -645,12 +702,12 @@ static void eapol_sm_processKey(struct eapol_sm *sm)
wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified");
key_len = be_to_host16(hdr->length) - sizeof(*key);
if (key_len > 32 || be_to_host16(key->key_length) > 32) {
if (key_len > 32 || rx_key_length > 32) {
wpa_printf(MSG_WARNING, "EAPOL: Too long key data length %d",
key_len ? key_len : be_to_host16(key->key_length));
key_len ? key_len : rx_key_length);
return;
}
if (key_len == be_to_host16(key->key_length)) {
if (key_len == rx_key_length) {
memcpy(ekey, key->key_iv, IEEE8021X_KEY_IV_LEN);
memcpy(ekey + IEEE8021X_KEY_IV_LEN, keydata.encr_key,
encr_key_len);
@ -660,22 +717,23 @@ static void eapol_sm_processKey(struct eapol_sm *sm)
wpa_hexdump_key(MSG_DEBUG, "EAPOL: Decrypted(RC4) key",
datakey, key_len);
} else if (key_len == 0) {
/* IEEE 802.1X-REV specifies that least significant Key Length
/*
* IEEE 802.1X-2004 specifies that least significant Key Length
* octets from MS-MPPE-Send-Key are used as the key if the key
* data is not present. This seems to be meaning the beginning
* of the MS-MPPE-Send-Key. In addition, MS-MPPE-Send-Key in
* Supplicant corresponds to MS-MPPE-Recv-Key in Authenticator.
* Anyway, taking the beginning of the keying material from EAP
* seems to interoperate with Authenticators. */
key_len = be_to_host16(key->key_length);
* seems to interoperate with Authenticators.
*/
key_len = rx_key_length;
memcpy(datakey, keydata.encr_key, key_len);
wpa_hexdump_key(MSG_DEBUG, "EAPOL: using part of EAP keying "
"material data encryption key",
datakey, key_len);
} else {
wpa_printf(MSG_DEBUG, "EAPOL: Invalid key data length %d "
"(key_length=%d)", key_len,
be_to_host16(key->key_length));
"(key_length=%d)", key_len, rx_key_length);
return;
}
@ -741,8 +799,8 @@ static void eapol_sm_txSuppRsp(struct eapol_sm *sm)
}
/* Send EAP-Packet from the EAP layer to the Authenticator */
sm->ctx->eapol_send(sm->ctx->ctx, IEEE802_1X_TYPE_EAP_PACKET,
resp, resp_len);
sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
IEEE802_1X_TYPE_EAP_PACKET, resp, resp_len);
/* eapRespData is not used anymore, so free it here */
free(resp);
@ -768,63 +826,20 @@ static void eapol_sm_abortSupp(struct eapol_sm *sm)
}
struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
{
struct eapol_sm *sm;
sm = malloc(sizeof(*sm));
if (sm == NULL)
return NULL;
memset(sm, 0, sizeof(*sm));
sm->ctx = ctx;
sm->portControl = Auto;
/* Supplicant PAE state machine */
sm->heldPeriod = 60;
sm->startPeriod = 30;
sm->maxStart = 3;
/* Supplicant Backend state machine */
sm->authPeriod = 30;
sm->eap = eap_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx);
if (sm->eap == NULL) {
free(sm);
return NULL;
}
/* Initialize EAPOL state machines */
sm->initialize = TRUE;
eapol_sm_step(sm);
sm->initialize = FALSE;
eapol_sm_step(sm);
eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
return sm;
}
void eapol_sm_deinit(struct eapol_sm *sm)
{
if (sm == NULL)
return;
eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
eap_sm_deinit(sm->eap);
free(sm->last_rx_key);
free(sm->eapReqData);
free(sm->ctx);
free(sm);
}
static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx)
{
eapol_sm_step(timeout_ctx);
}
/**
* eapol_sm_step - EAPOL state machine step function
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
*
* This function is called to notify the state machine about changed external
* variables. It will step through the EAPOL state machines in loop to process
* all triggered state changes.
*/
void eapol_sm_step(struct eapol_sm *sm)
{
int i;
@ -929,6 +944,17 @@ static const char * eapol_port_control(PortControl ctrl)
}
/**
* eapol_sm_configure - Set EAPOL variables
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
* @heldPeriod: dot1xSuppHeldPeriod
* @authPeriod: dot1xSuppAuthPeriod
* @startPeriod: dot1xSuppStartPeriod
* @maxStart: dot1xSuppMaxStart
*
* Set configurable EAPOL state machine variables. Each variable can be set to
* the given value or ignored if set to -1 (to set only some of the variables).
*/
void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
int startPeriod, int maxStart)
{
@ -945,6 +971,19 @@ void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
}
/**
* eapol_sm_get_status - Get EAPOL state machine status
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
* @buf: Buffer for status information
* @buflen: Maximum buffer length
* @verbose: Whether to include verbose status information
* Returns: Number of bytes written to buf.
*
* Query EAPOL state machine for status information. This function fills in a
* text area with current status information from the EAPOL state machine. If
* the buffer (buf) is not large enough, status information will be truncated
* to fit the buffer.
*/
int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
int verbose)
{
@ -960,10 +999,10 @@ int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
if (verbose) {
len += snprintf(buf + len, buflen - len,
"heldPeriod=%d\n"
"authPeriod=%d\n"
"startPeriod=%d\n"
"maxStart=%d\n"
"heldPeriod=%u\n"
"authPeriod=%u\n"
"startPeriod=%u\n"
"maxStart=%u\n"
"portControl=%s\n"
"Supplicant Backend state=%s\n",
sm->heldPeriod,
@ -980,6 +1019,18 @@ int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
}
/**
* eapol_sm_get_mib - Get EAPOL state machine MIBs
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
* @buf: Buffer for MIB information
* @buflen: Maximum buffer length
* Returns: Number of bytes written to buf.
*
* Query EAPOL state machine for MIB information. This function fills in a
* text area with current MIB information from the EAPOL state machine. If
* the buffer (buf) is not large enough, MIB information will be truncated to
* fit the buffer.
*/
int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen)
{
int len;
@ -987,22 +1038,22 @@ int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen)
return 0;
len = snprintf(buf, buflen,
"dot1xSuppPaeState=%d\n"
"dot1xSuppHeldPeriod=%d\n"
"dot1xSuppAuthPeriod=%d\n"
"dot1xSuppStartPeriod=%d\n"
"dot1xSuppMaxStart=%d\n"
"dot1xSuppHeldPeriod=%u\n"
"dot1xSuppAuthPeriod=%u\n"
"dot1xSuppStartPeriod=%u\n"
"dot1xSuppMaxStart=%u\n"
"dot1xSuppSuppControlledPortStatus=%s\n"
"dot1xSuppBackendPaeState=%d\n"
"dot1xSuppEapolFramesRx=%d\n"
"dot1xSuppEapolFramesTx=%d\n"
"dot1xSuppEapolStartFramesTx=%d\n"
"dot1xSuppEapolLogoffFramesTx=%d\n"
"dot1xSuppEapolRespFramesTx=%d\n"
"dot1xSuppEapolReqIdFramesRx=%d\n"
"dot1xSuppEapolReqFramesRx=%d\n"
"dot1xSuppInvalidEapolFramesRx=%d\n"
"dot1xSuppEapLengthErrorFramesRx=%d\n"
"dot1xSuppLastEapolFrameVersion=%d\n"
"dot1xSuppEapolFramesRx=%u\n"
"dot1xSuppEapolFramesTx=%u\n"
"dot1xSuppEapolStartFramesTx=%u\n"
"dot1xSuppEapolLogoffFramesTx=%u\n"
"dot1xSuppEapolRespFramesTx=%u\n"
"dot1xSuppEapolReqIdFramesRx=%u\n"
"dot1xSuppEapolReqFramesRx=%u\n"
"dot1xSuppInvalidEapolFramesRx=%u\n"
"dot1xSuppEapLengthErrorFramesRx=%u\n"
"dot1xSuppLastEapolFrameVersion=%u\n"
"dot1xSuppLastEapolFrameSource=" MACSTR "\n",
sm->SUPP_PAE_state,
sm->heldPeriod,
@ -1027,20 +1078,31 @@ int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen)
}
void eapol_sm_rx_eapol(struct eapol_sm *sm, u8 *src, u8 *buf, size_t len)
/**
* eapol_sm_rx_eapol - Process received EAPOL frames
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
* @src: Source MAC address of the EAPOL packet
* @buf: Pointer to the beginning of the EAPOL data (EAPOL header)
* @len: Length of the EAPOL frame
* Returns: 1 = EAPOL frame processed, 0 = not for EAPOL state machine,
* -1 failure
*/
int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
size_t len)
{
struct ieee802_1x_hdr *hdr;
struct ieee802_1x_eapol_key *key;
const struct ieee802_1x_hdr *hdr;
const struct ieee802_1x_eapol_key *key;
int plen, data_len;
int res = 1;
if (sm == NULL)
return;
return 0;
sm->dot1xSuppEapolFramesRx++;
if (len < sizeof(*hdr)) {
sm->dot1xSuppInvalidEapolFramesRx++;
return;
return 0;
}
hdr = (struct ieee802_1x_hdr *) buf;
hdr = (const struct ieee802_1x_hdr *) buf;
sm->dot1xSuppLastEapolFrameVersion = hdr->version;
memcpy(sm->dot1xSuppLastEapolFrameSource, src, ETH_ALEN);
if (hdr->version < EAPOL_VERSION) {
@ -1049,7 +1111,7 @@ void eapol_sm_rx_eapol(struct eapol_sm *sm, u8 *src, u8 *buf, size_t len)
plen = be_to_host16(hdr->length);
if (plen > len - sizeof(*hdr)) {
sm->dot1xSuppEapLengthErrorFramesRx++;
return;
return 0;
}
data_len = plen + sizeof(*hdr);
@ -1080,12 +1142,13 @@ void eapol_sm_rx_eapol(struct eapol_sm *sm, u8 *src, u8 *buf, size_t len)
"frame received");
break;
}
key = (struct ieee802_1x_eapol_key *) (hdr + 1);
key = (const struct ieee802_1x_eapol_key *) (hdr + 1);
if (key->type == EAPOL_KEY_TYPE_WPA ||
key->type == EAPOL_KEY_TYPE_RSN) {
/* WPA Supplicant takes care of this frame. */
wpa_printf(MSG_DEBUG, "EAPOL: Ignoring WPA EAPOL-Key "
"frame in EAPOL state machines");
res = 0;
break;
}
if (key->type != EAPOL_KEY_TYPE_RC4) {
@ -1110,9 +1173,18 @@ void eapol_sm_rx_eapol(struct eapol_sm *sm, u8 *src, u8 *buf, size_t len)
sm->dot1xSuppInvalidEapolFramesRx++;
break;
}
return res;
}
/**
* eapol_sm_notify_tx_eapol_key - Notification about transmitted EAPOL packet
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
*
* Notify EAPOL station machine about transmitted EAPOL packet from an external
* component, e.g., WPA. This will update the statistics.
*/
void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm)
{
if (sm)
@ -1120,6 +1192,13 @@ void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm)
}
/**
* eapol_sm_notify_portEnabled - Notification about portEnabled change
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
* @enabled: New portEnabled value
*
* Notify EAPOL station machine about new portEnabled value.
*/
void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled)
{
if (sm == NULL)
@ -1131,6 +1210,13 @@ void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled)
}
/**
* eapol_sm_notify_portValid - Notification about portValid change
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
* @valid: New portValid value
*
* Notify EAPOL station machine about new portValid value.
*/
void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid)
{
if (sm == NULL)
@ -1142,6 +1228,17 @@ void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid)
}
/**
* eapol_sm_notify_eap_success - Notification of external EAP success trigger
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
* @success: %TRUE = set success, %FALSE = clear success
*
* Notify EAPOL station machine that external event has forced EAP state to
* success (success = %TRUE). This can be cleared by setting success = %FALSE.
*
* This function is called to update EAP state when WPA-PSK key handshake has
* been completed successfully since WPA-PSK does not use EAP state machine.
*/
void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success)
{
if (sm == NULL)
@ -1156,6 +1253,14 @@ void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success)
}
/**
* eapol_sm_notify_eap_fail - Notification of external EAP failure trigger
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
* @fail: %TRUE = set failure, %FALSE = clear failure
*
* Notify EAPOL station machine that external event has forced EAP state to
* failure (fail = %TRUE). This can be cleared by setting fail = %FALSE.
*/
void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail)
{
if (sm == NULL)
@ -1168,8 +1273,20 @@ void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail)
}
/**
* eapol_sm_notify_config - Notification of EAPOL configuration change
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
* @config: Pointer to current network configuration
* @conf: Pointer to EAPOL configuration data
*
* Notify EAPOL station machine that configuration has changed. config will be
* stored as a backpointer to network configuration. This can be %NULL to clear
* the stored pointed. conf will be copied to local EAPOL/EAP configuration
* data. If conf is %NULL, this part of the configuration change will be
* skipped.
*/
void eapol_sm_notify_config(struct eapol_sm *sm, struct wpa_ssid *config,
struct eapol_config *conf)
const struct eapol_config *conf)
{
if (sm == NULL)
return;
@ -1185,13 +1302,25 @@ void eapol_sm_notify_config(struct eapol_sm *sm, struct wpa_ssid *config,
if (sm->eap) {
eap_set_fast_reauth(sm->eap, conf->fast_reauth);
eap_set_workaround(sm->eap, conf->workaround);
eap_set_force_disabled(sm->eap, conf->eap_disabled);
}
}
/**
* eapol_sm_get_key - Get master session key (MSK) from EAP
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
* @key: Pointer for key buffer
* @len: Number of bytes to copy to key
* Returns: 0 on success (len of key available), maximum available key len
* (>0) if key is available but it is shorter than len, or -1 on failure.
*
* Fetch EAP keying material (MSK, eapKeyData) from EAP state machine. The key
* is available only after a successful authentication.
*/
int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
{
u8 *eap_key;
const u8 *eap_key;
size_t eap_len;
if (sm == NULL || !eap_key_available(sm->eap))
@ -1206,6 +1335,13 @@ int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
}
/**
* eapol_sm_notify_logoff - Notification of logon/logoff commands
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
* @logoff: Whether command was logoff
*
* Notify EAPOL state machines that user requested logon/logoff.
*/
void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff)
{
if (sm) {
@ -1215,6 +1351,13 @@ void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff)
}
/**
* eapol_sm_notify_pmkid_attempt - Notification of successful PMKSA caching
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
*
* Notify EAPOL state machines that PMKSA caching was successful. This is used
* to move EAPOL and EAP state machines into authenticated/successful state.
*/
void eapol_sm_notify_cached(struct eapol_sm *sm)
{
if (sm == NULL)
@ -1225,6 +1368,13 @@ void eapol_sm_notify_cached(struct eapol_sm *sm)
}
/**
* eapol_sm_notify_pmkid_attempt - Notification of PMKSA caching
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
* @attempt: Whether PMKSA caching is tried
*
* Notify EAPOL state machines whether PMKSA caching is used.
*/
void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm, int attempt)
{
if (sm == NULL)
@ -1252,6 +1402,14 @@ static void eapol_sm_abort_cached(struct eapol_sm *sm)
}
/**
* eapol_sm_register_scard_ctx - Notification of smart card context
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
* @ctx: Context data for smart card operations
*
* Notify EAPOL state machines of context data for smart card operations. This
* context data will be used as a parameter for scard_*() functions.
*/
void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx)
{
if (sm) {
@ -1261,6 +1419,13 @@ void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx)
}
/**
* eapol_sm_notify_portControl - Notification of portControl changes
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
* @portControl: New value for portControl variable
*
* Notify EAPOL state machines that portControl variable has changed.
*/
void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl)
{
if (sm == NULL)
@ -1272,6 +1437,13 @@ void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl)
}
/**
* eapol_sm_notify_ctrl_attached - Notification of attached monitor
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
*
* Notify EAPOL state machines that a monitor was attached to the control
* interface to trigger re-sending of pending requests for user input.
*/
void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm)
{
if (sm == NULL)
@ -1280,6 +1452,13 @@ void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm)
}
/**
* eapol_sm_notify_ctrl_response - Notification of received user input
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
*
* Notify EAPOL state machines that a control response, i.e., user
* input, was received in order to trigger retrying of a pending EAP request.
*/
void eapol_sm_notify_ctrl_response(struct eapol_sm *sm)
{
if (sm == NULL)
@ -1295,6 +1474,37 @@ void eapol_sm_notify_ctrl_response(struct eapol_sm *sm)
}
/**
* eapol_sm_request_reauth - Request reauthentication
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
*
* This function can be used to request EAPOL reauthentication, e.g., when the
* current PMKSA entry is nearing expiration.
*/
void eapol_sm_request_reauth(struct eapol_sm *sm)
{
if (sm == NULL || sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED)
return;
eapol_sm_txStart(sm);
}
/**
* eapol_sm_notify_lower_layer_success - Notification of lower layer success
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
*
* Notify EAPOL (and EAP) state machines that a lower layer has detected a
* successful authentication. This is used to recover from dropped EAP-Success
* messages.
*/
void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm)
{
if (sm == NULL)
return;
eap_notify_lower_layer_success(sm->eap);
}
static struct wpa_ssid * eapol_sm_get_config(void *ctx)
{
struct eapol_sm *sm = ctx;
@ -1409,6 +1619,25 @@ static void eapol_sm_set_int(void *ctx, enum eapol_int_var variable,
}
static void eapol_sm_set_config_blob(void *ctx, struct wpa_config_blob *blob)
{
struct eapol_sm *sm = ctx;
if (sm && sm->ctx && sm->ctx->set_config_blob)
sm->ctx->set_config_blob(sm->ctx->ctx, blob);
}
static const struct wpa_config_blob *
eapol_sm_get_config_blob(void *ctx, const char *name)
{
struct eapol_sm *sm = ctx;
if (sm && sm->ctx && sm->ctx->get_config_blob)
return sm->ctx->get_config_blob(sm->ctx->ctx, name);
else
return NULL;
}
static struct eapol_callbacks eapol_cb =
{
.get_config = eapol_sm_get_config,
@ -1417,4 +1646,77 @@ static struct eapol_callbacks eapol_cb =
.get_int = eapol_sm_get_int,
.set_int = eapol_sm_set_int,
.get_eapReqData = eapol_sm_get_eapReqData,
.set_config_blob = eapol_sm_set_config_blob,
.get_config_blob = eapol_sm_get_config_blob,
};
/**
* eapol_sm_init - Initialize EAPOL state machine
* @ctx: Pointer to EAPOL context data; this needs to be an allocated buffer
* and EAPOL state machine will free it in eapol_sm_deinit()
* Returns: Pointer to the allocated EAPOL state machine or %NULL on failure
*
* Allocate and initialize an EAPOL state machine.
*/
struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
{
struct eapol_sm *sm;
struct eap_config conf;
sm = malloc(sizeof(*sm));
if (sm == NULL)
return NULL;
memset(sm, 0, sizeof(*sm));
sm->ctx = ctx;
sm->portControl = Auto;
/* Supplicant PAE state machine */
sm->heldPeriod = 60;
sm->startPeriod = 30;
sm->maxStart = 3;
/* Supplicant Backend state machine */
sm->authPeriod = 30;
memset(&conf, 0, sizeof(conf));
conf.opensc_engine_path = ctx->opensc_engine_path;
conf.pkcs11_engine_path = ctx->pkcs11_engine_path;
conf.pkcs11_module_path = ctx->pkcs11_module_path;
sm->eap = eap_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf);
if (sm->eap == NULL) {
free(sm);
return NULL;
}
/* Initialize EAPOL state machines */
sm->initialize = TRUE;
eapol_sm_step(sm);
sm->initialize = FALSE;
eapol_sm_step(sm);
eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
return sm;
}
/**
* eapol_sm_deinit - Deinitialize EAPOL state machine
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
*
* Deinitialize and free EAPOL state machine.
*/
void eapol_sm_deinit(struct eapol_sm *sm)
{
if (sm == NULL)
return;
eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
eap_sm_deinit(sm->eap);
free(sm->last_rx_key);
free(sm->eapReqData);
free(sm->ctx);
free(sm);
}

View file

@ -1,3 +1,17 @@
/*
* WPA Supplicant / EAPOL state machines
* Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef EAPOL_SM_H
#define EAPOL_SM_H
@ -6,28 +20,177 @@
typedef enum { Unauthorized, Authorized } PortStatus;
typedef enum { Auto, ForceUnauthorized, ForceAuthorized } PortControl;
/**
* struct eapol_config - Per network configuration for EAPOL state machines
*/
struct eapol_config {
/**
* accept_802_1x_keys - Accept IEEE 802.1X (non-WPA) EAPOL-Key frames
*
* This variable should be set to 1 when using EAPOL state machines
* with non-WPA security policy to generate dynamic WEP keys. When
* using WPA, this should be set to 0 so that WPA state machine can
* process the EAPOL-Key frames.
*/
int accept_802_1x_keys;
#define EAPOL_REQUIRE_KEY_UNICAST BIT(0)
#define EAPOL_REQUIRE_KEY_BROADCAST BIT(1)
int required_keys; /* which EAPOL-Key packets are required before
* marking connection authenticated */
int fast_reauth; /* whether fast EAP reauthentication is enabled */
int workaround; /* whether EAP workarounds are enabled */
/**
* required_keys - Which EAPOL-Key packets are required
*
* This variable determines which EAPOL-Key packets are required before
* marking connection authenticated. This is a bit field of
* EAPOL_REQUIRE_KEY_UNICAST and EAPOL_REQUIRE_KEY_BROADCAST flags.
*/
int required_keys;
/**
* fast_reauth - Whether fast EAP reauthentication is enabled
*/
int fast_reauth;
/**
* workaround - Whether EAP workarounds are enabled
*/
unsigned int workaround;
/**
* eap_disabled - Whether EAP is disabled
*/
int eap_disabled;
};
struct eapol_sm;
struct wpa_config_blob;
/**
* struct eapol_ctx - Global (for all networks) EAPOL state machine context
*/
struct eapol_ctx {
void *ctx; /* pointer to arbitrary upper level context */
int preauth; /* This EAPOL state machine is used for IEEE 802.11i/RSN
* pre-authentication */
/**
* ctx - Pointer to arbitrary upper level context
*/
void *ctx;
/**
* preauth - IEEE 802.11i/RSN pre-authentication
*
* This EAPOL state machine is used for IEEE 802.11i/RSN
* pre-authentication
*/
int preauth;
/**
* cb - Function to be called when EAPOL negotiation has been completed
* @eapol: Pointer to EAPOL state machine data
* @success: Whether the authentication was completed successfully
* @ctx: Pointer to context data (cb_ctx)
*
* This optional callback function will be called when the EAPOL
* authentication has been completed. This allows the owner of the
* EAPOL state machine to process the key and terminate the EAPOL state
* machine. Currently, this is used only in RSN pre-authentication.
*/
void (*cb)(struct eapol_sm *eapol, int success, void *ctx);
void *cb_ctx, *msg_ctx, *scard_ctx;
/**
* cb_ctx - Callback context for cb()
*/
void *cb_ctx;
/**
* msg_ctx - Callback context for wpa_msg() calls
*/
void *msg_ctx;
/**
* scard_ctx - Callback context for PC/SC scard_*() function calls
*
* This context can be updated with eapol_sm_register_scard_ctx().
*/
void *scard_ctx;
/**
* eapol_send_ctx - Callback context for eapol_send() calls
*/
void *eapol_send_ctx;
/**
* eapol_done_cb - Function to be called at successful completion
* @ctx: Callback context (ctx)
*
* This function is called at the successful completion of EAPOL
* authentication. If dynamic WEP keys are used, this is called only
* after all the expected keys have been received.
*/
void (*eapol_done_cb)(void *ctx);
int (*eapol_send)(void *ctx, int type, u8 *buf, size_t len);
/**
* eapol_send - Send EAPOL packets
* @ctx: Callback context (eapol_send_ctx)
* @type: EAPOL type (IEEE802_1X_TYPE_*)
* @buf: Pointer to EAPOL payload
* @len: Length of the EAPOL payload
* Returns: 0 on success, -1 on failure
*/
int (*eapol_send)(void *ctx, int type, const u8 *buf, size_t len);
/**
* set_wep_key - Configure WEP keys
* @ctx: Callback context (ctx)
* @unicast: Non-zero = unicast, 0 = multicast/broadcast key
* @keyidx: Key index (0..3)
* @key: WEP key
* @keylen: Length of the WEP key
* Returns: 0 on success, -1 on failure
*/
int (*set_wep_key)(void *ctx, int unicast, int keyidx,
u8 *key, size_t keylen);
const u8 *key, size_t keylen);
/**
* set_config_blob - Set or add a named configuration blob
* @ctx: Callback context (ctx)
* @blob: New value for the blob
*
* Adds a new configuration blob or replaces the current value of an
* existing blob.
*/
void (*set_config_blob)(void *ctx, struct wpa_config_blob *blob);
/**
* get_config_blob - Get a named configuration blob
* @ctx: Callback context (ctx)
* @name: Name of the blob
* Returns: Pointer to blob data or %NULL if not found
*/
const struct wpa_config_blob * (*get_config_blob)(void *ctx,
const char *name);
/**
* opensc_engine_path - Path to the OpenSSL engine for opensc
*
* This is an OpenSSL specific configuration option for loading OpenSC
* engine (engine_opensc.so); if %NULL, this engine is not loaded.
*/
const char *opensc_engine_path;
/**
* pkcs11_engine_path - Path to the OpenSSL engine for PKCS#11
*
* This is an OpenSSL specific configuration option for loading PKCS#11
* engine (engine_pkcs11.so); if %NULL, this engine is not loaded.
*/
const char *pkcs11_engine_path;
/**
* pkcs11_module_path - Path to the OpenSSL OpenSC/PKCS#11 module
*
* This is an OpenSSL specific configuration option for configuring
* path to OpenSC/PKCS#11 engine (opensc-pkcs11.so); if %NULL, this
* module is not loaded.
*/
const char *pkcs11_module_path;
};
@ -42,14 +205,15 @@ int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen);
void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
int startPeriod, int maxStart);
void eapol_sm_rx_eapol(struct eapol_sm *sm, u8 *src, u8 *buf, size_t len);
int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
size_t len);
void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm);
void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled);
void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid);
void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success);
void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail);
void eapol_sm_notify_config(struct eapol_sm *sm, struct wpa_ssid *config,
struct eapol_config *conf);
const struct eapol_config *conf);
int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len);
void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff);
void eapol_sm_notify_cached(struct eapol_sm *sm);
@ -58,9 +222,12 @@ void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx);
void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl);
void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm);
void eapol_sm_notify_ctrl_response(struct eapol_sm *sm);
void eapol_sm_request_reauth(struct eapol_sm *sm);
void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm);
#else /* IEEE8021X_EAPOL */
static inline struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
{
free(ctx);
return (struct eapol_sm *) 1;
}
static inline void eapol_sm_deinit(struct eapol_sm *sm)
@ -84,9 +251,10 @@ static inline void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod,
int maxStart)
{
}
static inline void eapol_sm_rx_eapol(struct eapol_sm *sm, u8 *src, u8 *buf,
size_t len)
static inline int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src,
const u8 *buf, size_t len)
{
return 0;
}
static inline void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm)
{
@ -133,6 +301,12 @@ static inline void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm)
static inline void eapol_sm_notify_ctrl_response(struct eapol_sm *sm)
{
}
static inline void eapol_sm_request_reauth(struct eapol_sm *sm)
{
}
static inline void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm)
{
}
#endif /* IEEE8021X_EAPOL */
#endif /* EAPOL_SM_H */

View file

@ -1,6 +1,15 @@
/*
* WPA Supplicant - test code
* Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
* Copyright (c) 2003-2006, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*
* IEEE 802.1X Supplicant test code (to be used in place of wpa_supplicant.c.
* Not used in production version.
@ -13,9 +22,11 @@
#include <ctype.h>
#include <string.h>
#include <signal.h>
#ifndef CONFIG_NATIVE_WINDOWS
#include <netinet/in.h>
#include <assert.h>
#include <arpa/inet.h>
#endif /* CONFIG_NATIVE_WINDOWS */
#include <assert.h>
#include "common.h"
#include "config.h"
@ -34,139 +45,147 @@
extern int wpa_debug_level;
extern int wpa_debug_show_keys;
static int eapol_test_num_reauths = 0;
static int no_mppe_keys = 0;
static int num_mppe_ok = 0, num_mppe_mismatch = 0;
struct wpa_driver_ops *wpa_supplicant_drivers[] = { };
struct eapol_test_data {
struct wpa_supplicant *wpa_s;
int eapol_test_num_reauths;
int no_mppe_keys;
int num_mppe_ok, num_mppe_mismatch;
u8 radius_identifier;
struct radius_msg *last_recv_radius;
struct in_addr own_ip_addr;
struct radius_client_data *radius;
struct hostapd_radius_servers *radius_conf;
u8 *last_eap_radius; /* last received EAP Response from Authentication
* Server */
size_t last_eap_radius_len;
u8 authenticator_pmk[PMK_LEN];
size_t authenticator_pmk_len;
int radius_access_accept_received;
int radius_access_reject_received;
int auth_timed_out;
u8 *eap_identity;
size_t eap_identity_len;
};
static struct eapol_test_data eapol_test;
static void send_eap_request_identity(void *eloop_ctx, void *timeout_ctx);
void wpa_msg(struct wpa_supplicant *wpa_s, int level, char *fmt, ...)
void hostapd_logger(void *ctx, u8 *addr, unsigned int module, int level,
char *fmt, ...)
{
char *format;
int maxlen;
va_list ap;
char *buf;
const int buflen = 2048;
int len;
buf = malloc(buflen);
if (buf == NULL) {
printf("Failed to allocate message buffer for:\n");
va_start(ap, fmt);
vprintf(fmt, ap);
printf("\n");
va_end(ap);
maxlen = strlen(fmt) + 100;
format = malloc(maxlen);
if (!format)
return;
}
va_start(ap, fmt);
len = vsnprintf(buf, buflen, fmt, ap);
if (addr)
snprintf(format, maxlen, "STA " MACSTR ": %s",
MAC2STR(addr), fmt);
else
snprintf(format, maxlen, "%s", fmt);
vprintf(format, ap);
printf("\n");
free(format);
va_end(ap);
wpa_printf(level, "%s", buf);
wpa_supplicant_ctrl_iface_send(wpa_s, level, buf, len);
free(buf);
}
void wpa_supplicant_event(struct wpa_supplicant *wpa_s, wpa_event_type event,
union wpa_event_data *data)
const char * hostapd_ip_txt(const struct hostapd_ip_addr *addr, char *buf,
size_t buflen)
{
if (buflen == 0 || addr == NULL)
return NULL;
if (addr->af == AF_INET) {
snprintf(buf, buflen, "%s", inet_ntoa(addr->u.v4));
} else {
buf[0] = '\0';
}
#ifdef CONFIG_IPV6
if (addr->af == AF_INET6) {
if (inet_ntop(AF_INET6, &addr->u.v6, buf, buflen) == NULL)
buf[0] = '\0';
}
#endif /* CONFIG_IPV6 */
return buf;
}
int rsn_preauth_init(struct wpa_supplicant *wpa_s, u8 *dst)
{
return -1;
}
void rsn_preauth_deinit(struct wpa_supplicant *wpa_s)
{
}
int pmksa_cache_list(struct wpa_supplicant *wpa_s, char *buf, size_t len)
{
return 0;
}
int wpa_get_mib(struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
{
return 0;
}
void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
{
}
const char * wpa_ssid_txt(u8 *ssid, size_t ssid_len)
{
return NULL;
}
int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
{
return -1;
}
static void ieee802_1x_encapsulate_radius(struct wpa_supplicant *wpa_s,
u8 *eap, size_t len)
static void ieee802_1x_encapsulate_radius(struct eapol_test_data *e,
const u8 *eap, size_t len)
{
struct radius_msg *msg;
char buf[128];
struct eap_hdr *hdr;
u8 *pos;
const struct eap_hdr *hdr;
const u8 *pos;
wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS "
"packet");
wpa_s->radius_identifier = radius_client_get_id(wpa_s);
e->radius_identifier = radius_client_get_id(e->radius);
msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST,
wpa_s->radius_identifier);
e->radius_identifier);
if (msg == NULL) {
printf("Could not create net RADIUS packet\n");
return;
}
radius_msg_make_authenticator(msg, (u8 *) wpa_s, sizeof(*wpa_s));
radius_msg_make_authenticator(msg, (u8 *) e, sizeof(*e));
hdr = (struct eap_hdr *) eap;
pos = (u8 *) (hdr + 1);
hdr = (const struct eap_hdr *) eap;
pos = (const u8 *) (hdr + 1);
if (len > sizeof(*hdr) && hdr->code == EAP_CODE_RESPONSE &&
pos[0] == EAP_TYPE_IDENTITY) {
pos++;
free(wpa_s->eap_identity);
wpa_s->eap_identity_len = len - sizeof(*hdr) - 1;
wpa_s->eap_identity = malloc(wpa_s->eap_identity_len);
if (wpa_s->eap_identity) {
memcpy(wpa_s->eap_identity, pos,
wpa_s->eap_identity_len);
free(e->eap_identity);
e->eap_identity_len = len - sizeof(*hdr) - 1;
e->eap_identity = malloc(e->eap_identity_len);
if (e->eap_identity) {
memcpy(e->eap_identity, pos, e->eap_identity_len);
wpa_hexdump(MSG_DEBUG, "Learned identity from "
"EAP-Response-Identity",
wpa_s->eap_identity,
wpa_s->eap_identity_len);
e->eap_identity, e->eap_identity_len);
}
}
if (wpa_s->eap_identity &&
if (e->eap_identity &&
!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME,
wpa_s->eap_identity,
wpa_s->eap_identity_len)) {
e->eap_identity, e->eap_identity_len)) {
printf("Could not add User-Name\n");
goto fail;
}
if (!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
(u8 *) &wpa_s->own_ip_addr, 4)) {
(u8 *) &e->own_ip_addr, 4)) {
printf("Could not add NAS-IP-Address\n");
goto fail;
}
snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
MAC2STR(wpa_s->own_addr));
MAC2STR(e->wpa_s->own_addr));
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
(u8 *) buf, strlen(buf))) {
printf("Could not add Calling-Station-Id\n");
@ -201,9 +220,9 @@ static void ieee802_1x_encapsulate_radius(struct wpa_supplicant *wpa_s,
/* State attribute must be copied if and only if this packet is
* Access-Request reply to the previous Access-Challenge */
if (wpa_s->last_recv_radius && wpa_s->last_recv_radius->hdr->code ==
if (e->last_recv_radius && e->last_recv_radius->hdr->code ==
RADIUS_CODE_ACCESS_CHALLENGE) {
int res = radius_msg_copy_attr(msg, wpa_s->last_recv_radius,
int res = radius_msg_copy_attr(msg, e->last_recv_radius,
RADIUS_ATTR_STATE);
if (res < 0) {
printf("Could not copy State attribute from previous "
@ -216,7 +235,7 @@ static void ieee802_1x_encapsulate_radius(struct wpa_supplicant *wpa_s,
}
}
radius_client_send(wpa_s, msg, RADIUS_AUTH, wpa_s->own_addr);
radius_client_send(e->radius, msg, RADIUS_AUTH, e->wpa_s->own_addr);
return;
fail:
@ -225,18 +244,35 @@ static void ieee802_1x_encapsulate_radius(struct wpa_supplicant *wpa_s,
}
static int eapol_test_eapol_send(void *ctx, int type, u8 *buf, size_t len)
static int eapol_test_eapol_send(void *ctx, int type, const u8 *buf,
size_t len)
{
struct wpa_supplicant *wpa_s = ctx;
printf("WPA: wpa_eapol_send(type=%d len=%d)\n", type, len);
/* struct wpa_supplicant *wpa_s = ctx; */
printf("WPA: eapol_test_eapol_send(type=%d len=%d)\n", type, len);
if (type == IEEE802_1X_TYPE_EAP_PACKET) {
wpa_hexdump(MSG_DEBUG, "TX EAP -> RADIUS", buf, len);
ieee802_1x_encapsulate_radius(wpa_s, buf, len);
ieee802_1x_encapsulate_radius(&eapol_test, buf, len);
}
return 0;
}
static void eapol_test_set_config_blob(void *ctx,
struct wpa_config_blob *blob)
{
struct wpa_supplicant *wpa_s = ctx;
wpa_config_set_blob(wpa_s->conf, blob);
}
static const struct wpa_config_blob *
eapol_test_get_config_blob(void *ctx, const char *name)
{
struct wpa_supplicant *wpa_s = ctx;
return wpa_config_get_blob(wpa_s->conf, name);
}
static void eapol_test_eapol_done_cb(void *ctx)
{
printf("WPA: EAPOL processing complete\n");
@ -245,40 +281,40 @@ static void eapol_test_eapol_done_cb(void *ctx)
static void eapol_sm_reauth(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
struct eapol_test_data *e = eloop_ctx;
printf("\n\n\n\n\neapol_test: Triggering EAP reauthentication\n\n");
wpa_s->radius_access_accept_received = 0;
send_eap_request_identity(eloop_ctx, timeout_ctx);
e->radius_access_accept_received = 0;
send_eap_request_identity(e->wpa_s, NULL);
}
static int eapol_test_compare_pmk(struct wpa_supplicant *wpa_s)
static int eapol_test_compare_pmk(struct eapol_test_data *e)
{
u8 pmk[PMK_LEN];
int ret = 1;
if (eapol_sm_get_key(wpa_s->eapol, pmk, PMK_LEN) == 0) {
if (eapol_sm_get_key(e->wpa_s->eapol, pmk, PMK_LEN) == 0) {
wpa_hexdump(MSG_DEBUG, "PMK from EAPOL", pmk, PMK_LEN);
if (memcmp(pmk, wpa_s->authenticator_pmk, PMK_LEN) != 0)
if (memcmp(pmk, e->authenticator_pmk, PMK_LEN) != 0)
printf("WARNING: PMK mismatch\n");
else if (wpa_s->radius_access_accept_received)
else if (e->radius_access_accept_received)
ret = 0;
} else if (wpa_s->authenticator_pmk_len == 16 &&
eapol_sm_get_key(wpa_s->eapol, pmk, 16) == 0) {
} else if (e->authenticator_pmk_len == 16 &&
eapol_sm_get_key(e->wpa_s->eapol, pmk, 16) == 0) {
wpa_hexdump(MSG_DEBUG, "LEAP PMK from EAPOL", pmk, 16);
if (memcmp(pmk, wpa_s->authenticator_pmk, 16) != 0)
if (memcmp(pmk, e->authenticator_pmk, 16) != 0)
printf("WARNING: PMK mismatch\n");
else if (wpa_s->radius_access_accept_received)
else if (e->radius_access_accept_received)
ret = 0;
} else if (wpa_s->radius_access_accept_received && no_mppe_keys) {
} else if (e->radius_access_accept_received && e->no_mppe_keys) {
/* No keying material expected */
ret = 0;
}
if (ret)
num_mppe_mismatch++;
else if (!no_mppe_keys)
num_mppe_ok++;
e->num_mppe_mismatch++;
else if (!e->no_mppe_keys)
e->num_mppe_ok++;
return ret;
}
@ -286,20 +322,20 @@ static int eapol_test_compare_pmk(struct wpa_supplicant *wpa_s)
static void eapol_sm_cb(struct eapol_sm *eapol, int success, void *ctx)
{
struct wpa_supplicant *wpa_s = ctx;
struct eapol_test_data *e = ctx;
printf("eapol_sm_cb: success=%d\n", success);
eapol_test_num_reauths--;
if (eapol_test_num_reauths < 0)
e->eapol_test_num_reauths--;
if (e->eapol_test_num_reauths < 0)
eloop_terminate();
else {
eapol_test_compare_pmk(wpa_s);
eloop_register_timeout(0, 100000, eapol_sm_reauth,
wpa_s, NULL);
eapol_test_compare_pmk(e);
eloop_register_timeout(0, 100000, eapol_sm_reauth, e, NULL);
}
}
static int test_eapol(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
static int test_eapol(struct eapol_test_data *e, struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
struct eapol_config eapol_conf;
struct eapol_ctx *ctx;
@ -314,10 +350,16 @@ static int test_eapol(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
ctx->msg_ctx = wpa_s;
ctx->scard_ctx = wpa_s->scard;
ctx->cb = eapol_sm_cb;
ctx->cb_ctx = wpa_s;
ctx->cb_ctx = e;
ctx->eapol_send_ctx = wpa_s;
ctx->preauth = 0;
ctx->eapol_done_cb = eapol_test_eapol_done_cb;
ctx->eapol_send = eapol_test_eapol_send;
ctx->set_config_blob = eapol_test_set_config_blob;
ctx->get_config_blob = eapol_test_get_config_blob;
ctx->opensc_engine_path = wpa_s->conf->opensc_engine_path;
ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
wpa_s->eapol = eapol_sm_init(ctx);
if (wpa_s->eapol == NULL) {
@ -344,22 +386,25 @@ static int test_eapol(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
}
static void test_eapol_clean(struct wpa_supplicant *wpa_s)
static void test_eapol_clean(struct eapol_test_data *e,
struct wpa_supplicant *wpa_s)
{
radius_client_deinit(wpa_s);
free(wpa_s->last_eap_radius);
if (wpa_s->last_recv_radius) {
radius_msg_free(wpa_s->last_recv_radius);
free(wpa_s->last_recv_radius);
radius_client_deinit(e->radius);
free(e->last_eap_radius);
if (e->last_recv_radius) {
radius_msg_free(e->last_recv_radius);
free(e->last_recv_radius);
}
free(wpa_s->eap_identity);
wpa_s->eap_identity = NULL;
free(e->eap_identity);
e->eap_identity = NULL;
eapol_sm_deinit(wpa_s->eapol);
wpa_s->eapol = NULL;
if (wpa_s->auth_server) {
free(wpa_s->auth_server->shared_secret);
free(wpa_s->auth_server);
if (e->radius_conf && e->radius_conf->auth_server) {
free(e->radius_conf->auth_server->shared_secret);
free(e->radius_conf->auth_server);
}
free(e->radius_conf);
e->radius_conf = NULL;
scard_deinit(wpa_s->scard);
wpa_supplicant_ctrl_iface_deinit(wpa_s);
wpa_config_free(wpa_s->conf);
@ -393,9 +438,9 @@ static void send_eap_request_identity(void *eloop_ctx, void *timeout_ctx)
static void eapol_test_timeout(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
struct eapol_test_data *e = eloop_ctx;
printf("EAPOL test timed out\n");
wpa_s->auth_timed_out = 1;
e->auth_timed_out = 1;
eloop_terminate();
}
@ -418,7 +463,7 @@ static char *eap_type_text(u8 type)
}
static void ieee802_1x_decapsulate_radius(struct wpa_supplicant *wpa_s)
static void ieee802_1x_decapsulate_radius(struct eapol_test_data *e)
{
u8 *eap;
size_t len;
@ -427,10 +472,10 @@ static void ieee802_1x_decapsulate_radius(struct wpa_supplicant *wpa_s)
char buf[64];
struct radius_msg *msg;
if (wpa_s->last_recv_radius == NULL)
if (e->last_recv_radius == NULL)
return;
msg = wpa_s->last_recv_radius;
msg = e->last_recv_radius;
eap = radius_msg_get_eap(msg, &len);
if (eap == NULL) {
@ -439,9 +484,9 @@ static void ieee802_1x_decapsulate_radius(struct wpa_supplicant *wpa_s)
* attribute */
wpa_printf(MSG_DEBUG, "could not extract "
"EAP-Message from RADIUS message");
free(wpa_s->last_eap_radius);
wpa_s->last_eap_radius = NULL;
wpa_s->last_eap_radius_len = 0;
free(e->last_eap_radius);
e->last_eap_radius = NULL;
e->last_eap_radius_len = 0;
return;
}
@ -487,10 +532,9 @@ static void ieee802_1x_decapsulate_radius(struct wpa_supplicant *wpa_s)
/* sta->eapol_sm->be_auth.idFromServer = hdr->identifier; */
if (wpa_s->last_eap_radius)
free(wpa_s->last_eap_radius);
wpa_s->last_eap_radius = eap;
wpa_s->last_eap_radius_len = len;
free(e->last_eap_radius);
e->last_eap_radius = eap;
e->last_eap_radius_len = len;
{
struct ieee802_1x_hdr *hdr;
@ -500,14 +544,14 @@ static void ieee802_1x_decapsulate_radius(struct wpa_supplicant *wpa_s)
hdr->type = IEEE802_1X_TYPE_EAP_PACKET;
hdr->length = htons(len);
memcpy((u8 *) (hdr + 1), eap, len);
eapol_sm_rx_eapol(wpa_s->eapol, wpa_s->bssid,
eapol_sm_rx_eapol(e->wpa_s->eapol, e->wpa_s->bssid,
(u8 *) hdr, sizeof(*hdr) + len);
free(hdr);
}
}
static void ieee802_1x_get_keys(struct wpa_supplicant *wpa_s,
static void ieee802_1x_get_keys(struct eapol_test_data *e,
struct radius_msg *msg, struct radius_msg *req,
u8 *shared_secret, size_t shared_secret_len)
{
@ -529,11 +573,11 @@ static void ieee802_1x_get_keys(struct wpa_supplicant *wpa_s,
if (keys->recv) {
wpa_hexdump(MSG_DEBUG, "MS-MPPE-Recv-Key (crypt)",
keys->recv, keys->recv_len);
wpa_s->authenticator_pmk_len =
e->authenticator_pmk_len =
keys->recv_len > PMK_LEN ? PMK_LEN :
keys->recv_len;
memcpy(wpa_s->authenticator_pmk, keys->recv,
wpa_s->authenticator_pmk_len);
memcpy(e->authenticator_pmk, keys->recv,
e->authenticator_pmk_len);
}
free(keys->send);
@ -545,11 +589,12 @@ static void ieee802_1x_get_keys(struct wpa_supplicant *wpa_s,
/* Process the RADIUS frames from Authentication Server */
static RadiusRxResult
ieee802_1x_receive_auth(struct wpa_supplicant *wpa_s,
struct radius_msg *msg, struct radius_msg *req,
ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
u8 *shared_secret, size_t shared_secret_len,
void *data)
{
struct eapol_test_data *e = data;
/* RFC 2869, Ch. 5.13: valid Message-Authenticator attribute MUST be
* present when packet contains an EAP-Message attribute */
if (msg->hdr->code == RADIUS_CODE_ACCESS_REJECT &&
@ -560,7 +605,7 @@ ieee802_1x_receive_auth(struct wpa_supplicant *wpa_s,
"Access-Reject without Message-Authenticator "
"since it does not include EAP-Message\n");
} else if (radius_msg_verify(msg, shared_secret, shared_secret_len,
req)) {
req, 1)) {
printf("Incoming RADIUS packet did not have correct "
"Message-Authenticator - dropped\n");
return RADIUS_RX_UNKNOWN;
@ -573,31 +618,31 @@ ieee802_1x_receive_auth(struct wpa_supplicant *wpa_s,
return RADIUS_RX_UNKNOWN;
}
wpa_s->radius_identifier = -1;
e->radius_identifier = -1;
wpa_printf(MSG_DEBUG, "RADIUS packet matching with station");
if (wpa_s->last_recv_radius) {
radius_msg_free(wpa_s->last_recv_radius);
free(wpa_s->last_recv_radius);
if (e->last_recv_radius) {
radius_msg_free(e->last_recv_radius);
free(e->last_recv_radius);
}
wpa_s->last_recv_radius = msg;
e->last_recv_radius = msg;
switch (msg->hdr->code) {
case RADIUS_CODE_ACCESS_ACCEPT:
wpa_s->radius_access_accept_received = 1;
ieee802_1x_get_keys(wpa_s, msg, req, shared_secret,
e->radius_access_accept_received = 1;
ieee802_1x_get_keys(e, msg, req, shared_secret,
shared_secret_len);
break;
case RADIUS_CODE_ACCESS_REJECT:
wpa_s->radius_access_reject_received = 1;
e->radius_access_reject_received = 1;
break;
}
ieee802_1x_decapsulate_radius(wpa_s);
ieee802_1x_decapsulate_radius(e);
if ((msg->hdr->code == RADIUS_CODE_ACCESS_ACCEPT &&
eapol_test_num_reauths < 0) ||
e->eapol_test_num_reauths < 0) ||
msg->hdr->code == RADIUS_CODE_ACCESS_REJECT) {
eloop_terminate();
}
@ -606,77 +651,8 @@ ieee802_1x_receive_auth(struct wpa_supplicant *wpa_s,
}
static void wpa_supplicant_imsi_identity(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
int aka = 0;
u8 *pos = ssid->eap_methods;
while (pos && *pos != EAP_TYPE_NONE) {
if (*pos == EAP_TYPE_AKA) {
aka = 1;
break;
}
pos++;
}
if (ssid->identity == NULL && wpa_s->imsi) {
ssid->identity = malloc(1 + wpa_s->imsi_len);
if (ssid->identity) {
ssid->identity[0] = aka ? '0' : '1';
memcpy(ssid->identity + 1, wpa_s->imsi,
wpa_s->imsi_len);
ssid->identity_len = 1 + wpa_s->imsi_len;
wpa_hexdump_ascii(MSG_DEBUG, "permanent identity from "
"IMSI", ssid->identity,
ssid->identity_len);
}
}
}
static void wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
char buf[100];
size_t len;
if (ssid->pcsc == NULL)
return;
if (wpa_s->scard != NULL) {
wpa_supplicant_imsi_identity(wpa_s, ssid);
return;
}
wpa_printf(MSG_DEBUG, "Selected network is configured to use SIM - "
"initialize PCSC");
wpa_s->scard = scard_init(SCARD_TRY_BOTH, ssid->pin);
if (wpa_s->scard == NULL) {
wpa_printf(MSG_WARNING, "Failed to initialize SIM "
"(pcsc-lite)");
/* TODO: what to do here? */
return;
}
eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard);
len = sizeof(buf);
if (scard_get_imsi(wpa_s->scard, buf, &len)) {
wpa_printf(MSG_WARNING, "Failed to get IMSI from SIM");
/* TODO: what to do here? */
return;
}
wpa_hexdump(MSG_DEBUG, "IMSI", (u8 *) buf, len);
free(wpa_s->imsi);
wpa_s->imsi = malloc(len);
if (wpa_s->imsi) {
memcpy(wpa_s->imsi, buf, len);
wpa_s->imsi_len = len;
wpa_supplicant_imsi_identity(wpa_s, ssid);
}
}
static void wpa_init_conf(struct wpa_supplicant *wpa_s, const char *authsrv,
static void wpa_init_conf(struct eapol_test_data *e,
struct wpa_supplicant *wpa_s, const char *authsrv,
int port, const char *secret)
{
struct hostapd_radius_server *as;
@ -684,24 +660,43 @@ static void wpa_init_conf(struct wpa_supplicant *wpa_s, const char *authsrv,
wpa_s->bssid[5] = 1;
wpa_s->own_addr[5] = 2;
wpa_s->own_ip_addr.s_addr = htonl((127 << 24) | 1);
e->own_ip_addr.s_addr = htonl((127 << 24) | 1);
strncpy(wpa_s->ifname, "test", sizeof(wpa_s->ifname));
wpa_s->num_auth_servers = 1;
e->radius_conf = malloc(sizeof(struct hostapd_radius_servers));
assert(e->radius_conf != NULL);
memset(e->radius_conf, 0, sizeof(struct hostapd_radius_servers));
e->radius_conf->num_auth_servers = 1;
as = malloc(sizeof(struct hostapd_radius_server));
assert(as != NULL);
inet_aton(authsrv, &as->addr);
memset(as, 0, sizeof(*as));
#ifdef CONFIG_NATIVE_WINDOWS
{
int a[4];
u8 *pos;
sscanf(authsrv, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]);
pos = (u8 *) &as->addr.u.v4;
*pos++ = a[0];
*pos++ = a[1];
*pos++ = a[2];
*pos++ = a[3];
}
#else /* CONFIG_NATIVE_WINDOWS */
inet_aton(authsrv, &as->addr.u.v4);
#endif /* CONFIG_NATIVE_WINDOWS */
as->addr.af = AF_INET;
as->port = port;
as->shared_secret = (u8 *) strdup(secret);
as->shared_secret_len = strlen(secret);
wpa_s->auth_server = wpa_s->auth_servers = as;
e->radius_conf->auth_server = as;
e->radius_conf->auth_servers = as;
e->radius_conf->msg_dumps = 1;
e->radius = radius_client_init(wpa_s, e->radius_conf);
assert(e->radius != NULL);
res = radius_client_init(wpa_s);
assert(res == 0);
res = radius_client_register(wpa_s, RADIUS_AUTH,
ieee802_1x_receive_auth, NULL);
res = radius_client_register(e->radius, RADIUS_AUTH,
ieee802_1x_receive_auth, e);
assert(res == 0);
}
@ -736,9 +731,14 @@ static int scard_test(void)
unsigned char aka_ik[IK_LEN];
unsigned char aka_ck[CK_LEN];
scard = scard_init(SCARD_TRY_BOTH, "1234");
scard = scard_init(SCARD_TRY_BOTH);
if (scard == NULL)
return -1;
if (scard_set_pin(scard, "1234")) {
wpa_printf(MSG_WARNING, "PIN validation failed");
scard_deinit(scard);
return -1;
}
len = sizeof(imsi);
if (scard_get_imsi(scard, imsi, &len))
@ -827,11 +827,16 @@ static int scard_get_triplets(int argc, char *argv[])
wpa_debug_level = 99;
}
scard = scard_init(SCARD_GSM_SIM_ONLY, argv[0]);
scard = scard_init(SCARD_GSM_SIM_ONLY);
if (scard == NULL) {
printf("Failed to open smartcard connection\n");
return -1;
}
if (scard_set_pin(scard, argv[0])) {
wpa_printf(MSG_WARNING, "PIN validation failed");
scard_deinit(scard);
return -1;
}
len = sizeof(imsi);
if (scard_get_imsi(scard, imsi, &len)) {
@ -877,7 +882,7 @@ static void eapol_test_terminate(int sig, void *eloop_ctx,
static void usage(void)
{
printf("usage:\n"
"eapol_test [-n] -c<conf> [-a<AS IP>] [-p<AS port>] "
"eapol_test [-nWS] -c<conf> [-a<AS IP>] [-p<AS port>] "
"[-s<AS secret>] [-r<count>]\n"
"eapol_test scard\n"
"eapol_test sim <PIN> <num triplets> [debug]\n"
@ -891,6 +896,8 @@ static void usage(void)
" -s<AS secret> = shared secret with the authentication "
"server, default 'radius'\n"
" -r<count> = number of re-authentications\n"
" -W = wait for a control interface monitor before starting\n"
" -S = save configuration after authentiation\n"
" -n = no MPPE keys expected\n");
}
@ -898,17 +905,27 @@ static void usage(void)
int main(int argc, char *argv[])
{
struct wpa_supplicant wpa_s;
int c, ret = 1;
int c, ret = 1, wait_for_monitor = 0, save_config = 0;
char *as_addr = "127.0.0.1";
int as_port = 1812;
char *as_secret = "radius";
char *conf = NULL;
#ifdef CONFIG_NATIVE_WINDOWS
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 0), &wsaData)) {
printf("Could not find a usable WinSock.dll\n");
return -1;
}
#endif /* CONFIG_NATIVE_WINDOWS */
memset(&eapol_test, 0, sizeof(eapol_test));
wpa_debug_level = 0;
wpa_debug_show_keys = 1;
for (;;) {
c = getopt(argc, argv, "a:c:np:r:s:");
c = getopt(argc, argv, "a:c:np:r:s:SW");
if (c < 0)
break;
switch (c) {
@ -919,17 +936,23 @@ int main(int argc, char *argv[])
conf = optarg;
break;
case 'n':
no_mppe_keys++;
eapol_test.no_mppe_keys++;
break;
case 'p':
as_port = atoi(optarg);
break;
case 'r':
eapol_test_num_reauths = atoi(optarg);
eapol_test.eapol_test_num_reauths = atoi(optarg);
break;
case 's':
as_secret = optarg;
break;
case 'S':
save_config++;
break;
case 'W':
wait_for_monitor++;
break;
default:
usage();
return -1;
@ -954,6 +977,7 @@ int main(int argc, char *argv[])
eloop_init(&wpa_s);
memset(&wpa_s, 0, sizeof(wpa_s));
eapol_test.wpa_s = &wpa_s;
wpa_s.conf = wpa_config_read(conf);
if (wpa_s.conf == NULL) {
printf("Failed to parse configuration file '%s'.\n", conf);
@ -964,7 +988,7 @@ int main(int argc, char *argv[])
return -1;
}
wpa_init_conf(&wpa_s, as_addr, as_port, as_secret);
wpa_init_conf(&eapol_test, &wpa_s, as_addr, as_port, as_secret);
if (wpa_supplicant_ctrl_iface_init(&wpa_s)) {
printf("Failed to initialize control interface '%s'.\n"
"You may have another eapol_test process already "
@ -976,37 +1000,50 @@ int main(int argc, char *argv[])
wpa_s.conf->ctrl_interface);
return -1;
}
wpa_supplicant_scard_init(&wpa_s, wpa_s.conf->ssid);
if (test_eapol(&wpa_s, wpa_s.conf->ssid))
if (wpa_supplicant_scard_init(&wpa_s, wpa_s.conf->ssid))
return -1;
eloop_register_timeout(30, 0, eapol_test_timeout, &wpa_s, NULL);
if (test_eapol(&eapol_test, &wpa_s, wpa_s.conf->ssid))
return -1;
if (wait_for_monitor)
wpa_supplicant_ctrl_iface_wait(&wpa_s);
eloop_register_timeout(30, 0, eapol_test_timeout, &eapol_test, NULL);
eloop_register_timeout(0, 0, send_eap_request_identity, &wpa_s, NULL);
eloop_register_signal(SIGINT, eapol_test_terminate, NULL);
eloop_register_signal(SIGTERM, eapol_test_terminate, NULL);
#ifndef CONFIG_NATIVE_WINDOWS
eloop_register_signal(SIGHUP, eapol_test_terminate, NULL);
#endif /* CONFIG_NATIVE_WINDOWS */
eloop_run();
if (eapol_test_compare_pmk(&wpa_s) == 0)
if (eapol_test_compare_pmk(&eapol_test) == 0)
ret = 0;
if (wpa_s.auth_timed_out)
if (eapol_test.auth_timed_out)
ret = -2;
if (wpa_s.radius_access_reject_received)
if (eapol_test.radius_access_reject_received)
ret = -3;
test_eapol_clean(&wpa_s);
if (save_config)
wpa_config_write(conf, wpa_s.conf);
test_eapol_clean(&eapol_test, &wpa_s);
eloop_destroy();
printf("MPPE keys OK: %d mismatch: %d\n",
num_mppe_ok, num_mppe_mismatch);
if (num_mppe_mismatch)
eapol_test.num_mppe_ok, eapol_test.num_mppe_mismatch);
if (eapol_test.num_mppe_mismatch)
ret = -4;
if (ret)
printf("FAILURE\n");
else
printf("SUCCESS\n");
#ifdef CONFIG_NATIVE_WINDOWS
WSACleanup();
#endif /* CONFIG_NATIVE_WINDOWS */
return ret;
}

View file

@ -1,5 +1,5 @@
/*
* Event loop
* Event loop based on select() loop
* Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
@ -294,10 +294,16 @@ int eloop_register_signal(int sig,
void eloop_run(void)
{
fd_set rfds;
fd_set *rfds;
int i, res;
struct timeval tv, now;
rfds = malloc(sizeof(*rfds));
if (rfds == NULL) {
printf("eloop_run - malloc failed\n");
return;
}
while (!eloop.terminate &&
(eloop.timeout || eloop.reader_count > 0)) {
if (eloop.timeout) {
@ -312,13 +318,14 @@ void eloop_run(void)
#endif
}
FD_ZERO(&rfds);
FD_ZERO(rfds);
for (i = 0; i < eloop.reader_count; i++)
FD_SET(eloop.readers[i].sock, &rfds);
res = select(eloop.max_sock + 1, &rfds, NULL, NULL,
FD_SET(eloop.readers[i].sock, rfds);
res = select(eloop.max_sock + 1, rfds, NULL, NULL,
eloop.timeout ? &tv : NULL);
if (res < 0 && errno != EINTR) {
perror("select");
free(rfds);
return;
}
eloop_process_pending_signals();
@ -342,7 +349,7 @@ void eloop_run(void)
continue;
for (i = 0; i < eloop.reader_count; i++) {
if (FD_ISSET(eloop.readers[i].sock, &rfds)) {
if (FD_ISSET(eloop.readers[i].sock, rfds)) {
eloop.readers[i].handler(
eloop.readers[i].sock,
eloop.readers[i].eloop_data,
@ -350,6 +357,8 @@ void eloop_run(void)
}
}
}
free(rfds);
}

View file

@ -1,53 +1,152 @@
/*
* Event loop
* Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*
* This file defines an event loop interface that supports processing events
* from registered timeouts (i.e., do something after N seconds), sockets
* (e.g., a new packet available for reading), and signals. eloop.c is an
* implementation of this interface using select() and sockets. This is
* suitable for most UNIX/POSIX systems. When porting to other operating
* systems, it may be necessary to replace that implementation with OS specific
* mechanisms.
*/
#ifndef ELOOP_H
#define ELOOP_H
/* Magic number for eloop_cancel_timeout() */
#define ELOOP_ALL_CTX (void *) -1
/* Initialize global event loop data - must be called before any other eloop_*
* function. user_data is a pointer to global data structure and will be passed
* as eloop_ctx to signal handlers. */
/**
* eloop_init() - Initialize global event loop data
* @user_data: Pointer to global data passed as eloop_ctx to signal handlers
*
* This function must be called before any other eloop_* function. user_data
* can be used to configure a global (to the process) pointer that will be
* passed as eloop_ctx parameter to signal handlers.
*/
void eloop_init(void *user_data);
/* Register handler for read event */
/**
* eloop_register_read_sock - Register handler for read events
* @sock: File descriptor number for the socket
* @handler: Callback function to be called when data is available for reading
* @eloop_data: Callback context data (eloop_ctx)
* @user_data: Callback context data (sock_ctx)
* Returns: 0 on success, -1 on failure
*
* Register a read socket notifier for the given file descriptor. The handler
* function will be called whenever data is available for reading from the
* socket.
*/
int eloop_register_read_sock(int sock,
void (*handler)(int sock, void *eloop_ctx,
void *sock_ctx),
void *eloop_data, void *user_data);
/**
* eloop_unregister_read_sock - Unregister handler for read events
* @sock: File descriptor number for the socket
*
* Unregister a read socket notifier that was previously registered with
* eloop_register_read_sock().
*/
void eloop_unregister_read_sock(int sock);
/* Register timeout */
/**
* eloop_register_timeout - Register timeout
* @secs: Number of seconds to the timeout
* @usecs: Number of microseconds to the timeout
* @handler: Callback function to be called when timeout occurs
* @eloop_data: Callback context data (eloop_ctx)
* @user_data: Callback context data (sock_ctx)
* Returns: 0 on success, -1 on failure
*
* Register a timeout that will cause the handler function to be called after
* given time.
*/
int eloop_register_timeout(unsigned int secs, unsigned int usecs,
void (*handler)(void *eloop_ctx, void *timeout_ctx),
void *eloop_data, void *user_data);
/* Cancel timeouts matching <handler,eloop_data,user_data>.
* ELOOP_ALL_CTX can be used as a wildcard for cancelling all timeouts
* regardless of eloop_data/user_data. */
/**
* eloop_cancel_timeout - Cancel timeouts
* @handler: Matching callback function
* @eloop_data: Matching eloop_data or %ELOOP_ALL_CTX to match all
* @user_data: Matching user_data or %ELOOP_ALL_CTX to match all
* Returns: Number of cancelled timeouts
*
* Cancel matching <handler,eloop_data,user_data> timeouts registered with
* eloop_register_timeout(). ELOOP_ALL_CTX can be used as a wildcard for
* cancelling all timeouts regardless of eloop_data/user_data.
*/
int eloop_cancel_timeout(void (*handler)(void *eloop_ctx, void *sock_ctx),
void *eloop_data, void *user_data);
/* Register handler for signal.
* Note: signals are 'global' events and there is no local eloop_data pointer
* like with other handlers. The (global) pointer given to eloop_init() will be
* used as eloop_ctx for signal handlers. */
int eloop_register_signal(int sock,
/**
* eloop_register_signal - Register handler for signals
* @sig: Signal number (e.g., SIGHUP)
* @handler: Callback function to be called when the signal is received
* @user_data: Callback context data (signal_ctx)
* Returns: 0 on success, -1 on failure
*
* Register a callback function that will be called when a signal is received.
* The calback function is actually called only after the system signal handler
* has returned. This means that the normal limits for sighandlers (i.e., only
* "safe functions" allowed) do not apply for the registered callback.
*
* Signals are 'global' events and there is no local eloop_data pointer like
* with other handlers. The global user_data pointer registered with
* eloop_init() will be used as eloop_ctx for signal handlers.
*/
int eloop_register_signal(int sig,
void (*handler)(int sig, void *eloop_ctx,
void *signal_ctx),
void *user_data);
/* Start event loop and continue running as long as there are any registered
* event handlers. */
/**
* eloop_run - Start the event loop
*
* Start the event loop and continue running as long as there are any
* registered event handlers. This function is run after event loop has been
* initialized with event_init() and one or more events have been registered.
*/
void eloop_run(void);
/* Terminate event loop even if there are registered events. */
/**
* eloop_terminate - Terminate event loop
*
* Terminate event loop even if there are registered events. This can be used
* to request the program to be terminated cleanly.
*/
void eloop_terminate(void);
/* Free any reserved resources. After calling eloop_destoy(), other eloop_*
* functions must not be called before re-running eloop_init(). */
/**
* eloop_destroy - Free any resources allocated for the event loop
*
* After calling eloop_destoy(), other eloop_* functions must not be called
* before re-running eloop_init().
*/
void eloop_destroy(void);
/* Check whether event loop has been terminated. */
/**
* eloop_terminated - Check whether event loop has been terminated
* Returns: 1 = event loop terminate, 0 = event loop still running
*
* This function can be used to check whether eloop_terminate() has been called
* to request termination of the event loop. This is normally used to abort
* operations that may still be queued to be run when eloop_terminate() was
* called.
*/
int eloop_terminated(void);
#endif /* ELOOP_H */

View file

@ -0,0 +1,759 @@
/*
* WPA Supplicant - Driver event processing
* Copyright (c) 2003-2006, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include "common.h"
#include "eapol_sm.h"
#include "wpa.h"
#include "eloop.h"
#include "wpa_supplicant.h"
#include "config.h"
#include "l2_packet.h"
#include "wpa_supplicant_i.h"
#include "pcsc_funcs.h"
#include "preauth.h"
#include "wpa_ctrl.h"
#include "eap.h"
static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
{
struct wpa_ssid *ssid;
if (wpa_s->conf->ap_scan == 1 && wpa_s->current_ssid)
return 0;
ssid = wpa_supplicant_get_ssid(wpa_s);
if (ssid == NULL) {
wpa_printf(MSG_INFO, "No network configuration found for the "
"current AP");
return -1;
}
if (ssid->disabled) {
wpa_printf(MSG_DEBUG, "Selected network is disabled");
return -1;
}
wpa_printf(MSG_DEBUG, "Network configuration found for the current "
"AP");
if (ssid->key_mgmt & (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X |
WPA_KEY_MGMT_WPA_NONE)) {
u8 wpa_ie[80];
size_t wpa_ie_len = sizeof(wpa_ie);
wpa_supplicant_set_suites(wpa_s, NULL, ssid,
wpa_ie, &wpa_ie_len);
} else {
wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
}
wpa_s->current_ssid = ssid;
wpa_sm_set_config(wpa_s->wpa, wpa_s->current_ssid);
wpa_supplicant_initiate_eapol(wpa_s);
return 0;
}
static void wpa_supplicant_stop_countermeasures(void *eloop_ctx,
void *sock_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
if (wpa_s->countermeasures) {
wpa_s->countermeasures = 0;
wpa_drv_set_countermeasures(wpa_s, 0);
wpa_msg(wpa_s, MSG_INFO, "WPA: TKIP countermeasures stopped");
wpa_supplicant_req_scan(wpa_s, 0, 0);
}
}
static void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
{
wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
memset(wpa_s->bssid, 0, ETH_ALEN);
eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
if (wpa_s->key_mgmt == WPA_KEY_MGMT_PSK)
eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
}
static void wpa_find_assoc_pmkid(struct wpa_supplicant *wpa_s)
{
struct wpa_ie_data ie;
int i, pmksa_set = -1;
if (wpa_sm_parse_own_wpa_ie(wpa_s->wpa, &ie) < 0 ||
ie.pmkid == NULL)
return;
for (i = 0; i < ie.num_pmkid; i++) {
pmksa_set = pmksa_cache_set_current(wpa_s->wpa,
ie.pmkid + i * PMKID_LEN,
NULL, NULL, 0);
if (pmksa_set == 0) {
eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1);
break;
}
}
wpa_printf(MSG_DEBUG, "RSN: PMKID from assoc IE %sfound from PMKSA "
"cache", pmksa_set == 0 ? "" : "not ");
}
static void wpa_supplicant_event_pmkid_candidate(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
{
if (data == NULL) {
wpa_printf(MSG_DEBUG, "RSN: No data in PMKID candidate event");
return;
}
wpa_printf(MSG_DEBUG, "RSN: PMKID candidate event - bssid=" MACSTR
" index=%d preauth=%d",
MAC2STR(data->pmkid_candidate.bssid),
data->pmkid_candidate.index,
data->pmkid_candidate.preauth);
pmksa_candidate_add(wpa_s->wpa, data->pmkid_candidate.bssid,
data->pmkid_candidate.index,
data->pmkid_candidate.preauth);
}
static int wpa_supplicant_dynamic_keys(struct wpa_supplicant *wpa_s)
{
if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE)
return 0;
if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
wpa_s->current_ssid &&
!(wpa_s->current_ssid->eapol_flags &
(EAPOL_FLAG_REQUIRE_KEY_UNICAST |
EAPOL_FLAG_REQUIRE_KEY_BROADCAST))) {
/* IEEE 802.1X, but not using dynamic WEP keys (i.e., either
* plaintext or static WEP keys). */
return 0;
}
return 1;
}
/**
* wpa_supplicant_scard_init - Initialize SIM/USIM access with PC/SC
* @wpa_s: pointer to wpa_supplicant data
* @ssid: Configuration data for the network
* Returns: 0 on success, -1 on failure
*
* This function is called when starting authentication with a network that is
* configured to use PC/SC for SIM/USIM access (EAP-SIM or EAP-AKA).
*/
int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
int aka = 0, sim = 0, type;
if (ssid->pcsc == NULL || wpa_s->scard != NULL)
return 0;
if (ssid->eap_methods == NULL) {
sim = 1;
aka = 1;
} else {
u8 *eap = ssid->eap_methods;
while (*eap != EAP_TYPE_NONE) {
if (*eap == EAP_TYPE_SIM)
sim = 1;
else if (*eap == EAP_TYPE_AKA)
aka = 1;
eap++;
}
}
#ifndef EAP_SIM
sim = 0;
#endif /* EAP_SIM */
#ifndef EAP_AKA
aka = 0;
#endif /* EAP_AKA */
if (!sim && !aka) {
wpa_printf(MSG_DEBUG, "Selected network is configured to use "
"SIM, but neither EAP-SIM nor EAP-AKA are enabled");
return 0;
}
wpa_printf(MSG_DEBUG, "Selected network is configured to use SIM "
"(sim=%d aka=%d) - initialize PCSC", sim, aka);
if (sim && aka)
type = SCARD_TRY_BOTH;
else if (aka)
type = SCARD_USIM_ONLY;
else
type = SCARD_GSM_SIM_ONLY;
wpa_s->scard = scard_init(type);
if (wpa_s->scard == NULL) {
wpa_printf(MSG_WARNING, "Failed to initialize SIM "
"(pcsc-lite)");
return -1;
}
wpa_sm_set_scard_ctx(wpa_s->wpa, wpa_s->scard);
eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard);
return 0;
}
static int wpa_supplicant_match_privacy(struct wpa_scan_result *bss,
struct wpa_ssid *ssid)
{
int i, privacy = 0;
for (i = 0; i < NUM_WEP_KEYS; i++) {
if (ssid->wep_key_len[i]) {
privacy = 1;
break;
}
}
if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
ssid->eapol_flags & (EAPOL_FLAG_REQUIRE_KEY_UNICAST |
EAPOL_FLAG_REQUIRE_KEY_BROADCAST))
privacy = 1;
if (bss->caps & IEEE80211_CAP_PRIVACY)
return privacy;
return !privacy;
}
static int wpa_supplicant_ssid_bss_match(struct wpa_ssid *ssid,
struct wpa_scan_result *bss)
{
struct wpa_ie_data ie;
int proto_match = 0;
while ((ssid->proto & WPA_PROTO_RSN) && bss->rsn_ie_len > 0) {
proto_match++;
if (wpa_parse_wpa_ie(bss->rsn_ie, bss->rsn_ie_len, &ie)) {
wpa_printf(MSG_DEBUG, " skip RSN IE - parse failed");
break;
}
if (!(ie.proto & ssid->proto)) {
wpa_printf(MSG_DEBUG, " skip RSN IE - proto "
"mismatch");
break;
}
if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) {
wpa_printf(MSG_DEBUG, " skip RSN IE - PTK cipher "
"mismatch");
break;
}
if (!(ie.group_cipher & ssid->group_cipher)) {
wpa_printf(MSG_DEBUG, " skip RSN IE - GTK cipher "
"mismatch");
break;
}
if (!(ie.key_mgmt & ssid->key_mgmt)) {
wpa_printf(MSG_DEBUG, " skip RSN IE - key mgmt "
"mismatch");
break;
}
wpa_printf(MSG_DEBUG, " selected based on RSN IE");
return 1;
}
while ((ssid->proto & WPA_PROTO_WPA) && bss->wpa_ie_len > 0) {
proto_match++;
if (wpa_parse_wpa_ie(bss->wpa_ie, bss->wpa_ie_len, &ie)) {
wpa_printf(MSG_DEBUG, " skip WPA IE - parse failed");
break;
}
if (!(ie.proto & ssid->proto)) {
wpa_printf(MSG_DEBUG, " skip WPA IE - proto "
"mismatch");
break;
}
if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) {
wpa_printf(MSG_DEBUG, " skip WPA IE - PTK cipher "
"mismatch");
break;
}
if (!(ie.group_cipher & ssid->group_cipher)) {
wpa_printf(MSG_DEBUG, " skip WPA IE - GTK cipher "
"mismatch");
break;
}
if (!(ie.key_mgmt & ssid->key_mgmt)) {
wpa_printf(MSG_DEBUG, " skip WPA IE - key mgmt "
"mismatch");
break;
}
wpa_printf(MSG_DEBUG, " selected based on WPA IE");
return 1;
}
if (proto_match == 0)
wpa_printf(MSG_DEBUG, " skip - no WPA/RSN proto match");
return 0;
}
static struct wpa_scan_result *
wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s, struct wpa_ssid *group,
struct wpa_scan_result *results, int num,
struct wpa_ssid **selected_ssid)
{
struct wpa_ssid *ssid;
struct wpa_scan_result *bss, *selected = NULL;
int i;
struct wpa_blacklist *e;
wpa_printf(MSG_DEBUG, "Selecting BSS from priority group %d",
group->priority);
bss = NULL;
ssid = NULL;
/* First, try to find WPA-enabled AP */
for (i = 0; i < num && !selected; i++) {
bss = &results[i];
wpa_printf(MSG_DEBUG, "%d: " MACSTR " ssid='%s' "
"wpa_ie_len=%lu rsn_ie_len=%lu caps=0x%x",
i, MAC2STR(bss->bssid),
wpa_ssid_txt(bss->ssid, bss->ssid_len),
(unsigned long) bss->wpa_ie_len,
(unsigned long) bss->rsn_ie_len, bss->caps);
if ((e = wpa_blacklist_get(wpa_s, bss->bssid)) &&
e->count > 1) {
wpa_printf(MSG_DEBUG, " skip - blacklisted");
continue;
}
if (bss->wpa_ie_len == 0 && bss->rsn_ie_len == 0) {
wpa_printf(MSG_DEBUG, " skip - no WPA/RSN IE");
continue;
}
for (ssid = group; ssid; ssid = ssid->pnext) {
if (ssid->disabled)
continue;
if (bss->ssid_len != ssid->ssid_len ||
memcmp(bss->ssid, ssid->ssid,
bss->ssid_len) != 0) {
wpa_printf(MSG_DEBUG, " skip - "
"SSID mismatch");
continue;
}
if (ssid->bssid_set &&
memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0) {
wpa_printf(MSG_DEBUG, " skip - "
"BSSID mismatch");
continue;
}
if (wpa_supplicant_ssid_bss_match(ssid, bss)) {
selected = bss;
*selected_ssid = ssid;
break;
}
}
}
/* If no WPA-enabled AP found, try to find non-WPA AP, if configuration
* allows this. */
for (i = 0; i < num && !selected; i++) {
bss = &results[i];
if ((e = wpa_blacklist_get(wpa_s, bss->bssid)) &&
e->count > 1) {
continue;
}
for (ssid = group; ssid; ssid = ssid->pnext) {
if (!ssid->disabled &&
(ssid->ssid_len == 0 ||
(bss->ssid_len == ssid->ssid_len &&
memcmp(bss->ssid, ssid->ssid, bss->ssid_len) ==
0)) &&
(!ssid->bssid_set ||
memcmp(bss->bssid, ssid->bssid, ETH_ALEN) == 0) &&
((ssid->key_mgmt & WPA_KEY_MGMT_NONE) ||
(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA))
&& bss->wpa_ie_len == 0 && bss->rsn_ie_len == 0 &&
wpa_supplicant_match_privacy(bss, ssid) &&
!(bss->caps & IEEE80211_CAP_IBSS))
{
selected = bss;
*selected_ssid = ssid;
wpa_printf(MSG_DEBUG, " selected non-WPA AP "
MACSTR " ssid='%s'",
MAC2STR(bss->bssid),
wpa_ssid_txt(bss->ssid,
bss->ssid_len));
break;
}
}
}
return selected;
}
static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s)
{
int num, prio;
struct wpa_scan_result *selected = NULL;
struct wpa_ssid *ssid = NULL;
struct wpa_scan_result *results;
if (wpa_supplicant_get_scan_results(wpa_s) < 0) {
if (wpa_s->conf->ap_scan == 2)
return;
wpa_printf(MSG_DEBUG, "Failed to get scan results - try "
"scanning again");
wpa_supplicant_req_scan(wpa_s, 1, 0);
return;
}
if (wpa_s->conf->ap_scan == 2)
return;
results = wpa_s->scan_results;
num = wpa_s->num_scan_results;
while (selected == NULL) {
for (prio = 0; prio < wpa_s->conf->num_prio; prio++) {
selected = wpa_supplicant_select_bss(
wpa_s, wpa_s->conf->pssid[prio], results, num,
&ssid);
if (selected)
break;
}
if (selected == NULL && wpa_s->blacklist) {
wpa_printf(MSG_DEBUG, "No APs found - clear blacklist "
"and try again");
wpa_blacklist_clear(wpa_s);
} else if (selected == NULL) {
break;
}
}
if (selected) {
if (wpa_s->reassociate ||
memcmp(selected->bssid, wpa_s->bssid, ETH_ALEN) != 0) {
if (wpa_supplicant_scard_init(wpa_s, ssid)) {
wpa_supplicant_req_scan(wpa_s, 10, 0);
return;
}
wpa_supplicant_associate(wpa_s, selected, ssid);
} else {
wpa_printf(MSG_DEBUG, "Already associated with the "
"selected AP.");
}
rsn_preauth_scan_results(wpa_s->wpa, results, num);
} else {
wpa_printf(MSG_DEBUG, "No suitable AP found.");
wpa_supplicant_req_scan(wpa_s, 5, 0);
}
}
static void wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
{
int l, len, found = 0, wpa_found, rsn_found;
u8 *p;
wpa_printf(MSG_DEBUG, "Association info event");
if (data->assoc_info.req_ies)
wpa_hexdump(MSG_DEBUG, "req_ies", data->assoc_info.req_ies,
data->assoc_info.req_ies_len);
if (data->assoc_info.resp_ies)
wpa_hexdump(MSG_DEBUG, "resp_ies", data->assoc_info.resp_ies,
data->assoc_info.resp_ies_len);
if (data->assoc_info.beacon_ies)
wpa_hexdump(MSG_DEBUG, "beacon_ies",
data->assoc_info.beacon_ies,
data->assoc_info.beacon_ies_len);
p = data->assoc_info.req_ies;
l = data->assoc_info.req_ies_len;
/* Go through the IEs and make a copy of the WPA/RSN IE, if present. */
while (p && l >= 2) {
len = p[1] + 2;
if (len > l) {
wpa_hexdump(MSG_DEBUG, "Truncated IE in assoc_info",
p, l);
break;
}
if ((p[0] == GENERIC_INFO_ELEM && p[1] >= 6 &&
(memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0)) ||
(p[0] == RSN_INFO_ELEM && p[1] >= 2)) {
if (wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, p, len))
break;
found = 1;
wpa_find_assoc_pmkid(wpa_s);
break;
}
l -= len;
p += len;
}
if (!found && data->assoc_info.req_ies)
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
/* WPA/RSN IE from Beacon/ProbeResp */
p = data->assoc_info.beacon_ies;
l = data->assoc_info.beacon_ies_len;
/* Go through the IEs and make a copy of the WPA/RSN IEs, if present.
*/
wpa_found = rsn_found = 0;
while (p && l >= 2) {
len = p[1] + 2;
if (len > l) {
wpa_hexdump(MSG_DEBUG, "Truncated IE in beacon_ies",
p, l);
break;
}
if (!wpa_found &&
p[0] == GENERIC_INFO_ELEM && p[1] >= 6 &&
memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0) {
wpa_found = 1;
wpa_sm_set_ap_wpa_ie(wpa_s->wpa, p, len);
}
if (!rsn_found &&
p[0] == RSN_INFO_ELEM && p[1] >= 2) {
rsn_found = 1;
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, p, len);
}
l -= len;
p += len;
}
if (!wpa_found && data->assoc_info.beacon_ies)
wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0);
if (!rsn_found && data->assoc_info.beacon_ies)
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0);
}
static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
{
u8 bssid[ETH_ALEN];
if (data)
wpa_supplicant_event_associnfo(wpa_s, data);
wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATED);
if (wpa_drv_get_bssid(wpa_s, bssid) >= 0 &&
memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0) {
wpa_msg(wpa_s, MSG_DEBUG, "Associated to a new BSS: BSSID="
MACSTR, MAC2STR(bssid));
memcpy(wpa_s->bssid, bssid, ETH_ALEN);
if (wpa_supplicant_dynamic_keys(wpa_s)) {
wpa_clear_keys(wpa_s, bssid);
}
if (wpa_supplicant_select_config(wpa_s) < 0) {
wpa_supplicant_disassociate(wpa_s,
REASON_DEAUTH_LEAVING);
return;
}
}
wpa_msg(wpa_s, MSG_INFO, "Associated with " MACSTR, MAC2STR(bssid));
if (wpa_s->current_ssid) {
/* When using scanning (ap_scan=1), SIM PC/SC interface can be
* initialized before association, but for other modes,
* initialize PC/SC here, if the current configuration needs
* smartcard or SIM/USIM. */
wpa_supplicant_scard_init(wpa_s, wpa_s->current_ssid);
}
wpa_sm_notify_assoc(wpa_s->wpa, bssid);
l2_packet_notify_auth_start(wpa_s->l2);
/*
* Set portEnabled first to FALSE in order to get EAP state machine out
* of the SUCCESS state and eapSuccess cleared. Without this, EAPOL PAE
* state machine may transit to AUTHENTICATING state based on obsolete
* eapSuccess and then trigger BE_AUTH to SUCCESS and PAE to
* AUTHENTICATED without ever giving chance to EAP state machine to
* reset the state.
*/
eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
if (wpa_s->key_mgmt == WPA_KEY_MGMT_PSK)
eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
/* 802.1X::portControl = Auto */
eapol_sm_notify_portEnabled(wpa_s->eapol, TRUE);
wpa_s->eapol_received = 0;
if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
wpa_supplicant_cancel_auth_timeout(wpa_s);
wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
} else {
/* Timeout for receiving the first EAPOL packet */
wpa_supplicant_req_auth_timeout(wpa_s, 10, 0);
}
}
static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s)
{
if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
/*
* At least Host AP driver and a Prism3 card seemed to be
* generating streams of disconnected events when configuring
* IBSS for WPA-None. Ignore them for now.
*/
wpa_printf(MSG_DEBUG, "Disconnect event - ignore in "
"IBSS/WPA-None mode");
return;
}
if (wpa_s->wpa_state == WPA_4WAY_HANDSHAKE &&
wpa_s->key_mgmt == WPA_KEY_MGMT_PSK) {
wpa_msg(wpa_s, MSG_INFO, "WPA: 4-Way Handshake failed - "
"pre-shared key may be incorrect");
}
if (wpa_s->wpa_state >= WPA_ASSOCIATED)
wpa_supplicant_req_scan(wpa_s, 0, 100000);
wpa_blacklist_add(wpa_s, wpa_s->bssid);
wpa_sm_notify_disassoc(wpa_s->wpa);
wpa_supplicant_mark_disassoc(wpa_s);
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "- Disconnect event - "
"remove keys");
if (wpa_supplicant_dynamic_keys(wpa_s)) {
wpa_s->keys_cleared = 0;
wpa_clear_keys(wpa_s, wpa_s->bssid);
}
}
static void
wpa_supplicant_event_michael_mic_failure(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
{
int pairwise;
time_t now;
wpa_msg(wpa_s, MSG_WARNING, "Michael MIC failure detected");
pairwise = (data && data->michael_mic_failure.unicast);
wpa_sm_key_request(wpa_s->wpa, 1, pairwise);
time(&now);
if (wpa_s->last_michael_mic_error &&
now - wpa_s->last_michael_mic_error <= 60) {
/* initialize countermeasures */
wpa_s->countermeasures = 1;
wpa_msg(wpa_s, MSG_WARNING, "TKIP countermeasures started");
/*
* Need to wait for completion of request frame. We do not get
* any callback for the message completion, so just wait a
* short while and hope for the best. */
usleep(10000);
wpa_drv_set_countermeasures(wpa_s, 1);
wpa_supplicant_deauthenticate(wpa_s,
REASON_MICHAEL_MIC_FAILURE);
eloop_cancel_timeout(wpa_supplicant_stop_countermeasures,
wpa_s, NULL);
eloop_register_timeout(60, 0,
wpa_supplicant_stop_countermeasures,
wpa_s, NULL);
/* TODO: mark the AP rejected for 60 second. STA is
* allowed to associate with another AP.. */
}
wpa_s->last_michael_mic_error = now;
}
static void
wpa_supplicant_event_interface_status(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
{
if (strcmp(wpa_s->ifname, data->interface_status.ifname) != 0)
return;
switch (data->interface_status.ievent) {
case EVENT_INTERFACE_ADDED:
if (!wpa_s->interface_removed)
break;
wpa_s->interface_removed = 0;
wpa_printf(MSG_DEBUG, "Configured interface was added.");
if (wpa_supplicant_driver_init(wpa_s, 1) < 0) {
wpa_printf(MSG_INFO, "Failed to initialize the driver "
"after interface was added.");
}
break;
case EVENT_INTERFACE_REMOVED:
wpa_printf(MSG_DEBUG, "Configured interface was removed.");
wpa_s->interface_removed = 1;
wpa_supplicant_mark_disassoc(wpa_s);
l2_packet_deinit(wpa_s->l2);
wpa_s->l2 = NULL;
break;
}
}
void wpa_supplicant_event(struct wpa_supplicant *wpa_s, wpa_event_type event,
union wpa_event_data *data)
{
switch (event) {
case EVENT_ASSOC:
wpa_supplicant_event_assoc(wpa_s, data);
break;
case EVENT_DISASSOC:
wpa_supplicant_event_disassoc(wpa_s);
break;
case EVENT_MICHAEL_MIC_FAILURE:
wpa_supplicant_event_michael_mic_failure(wpa_s, data);
break;
case EVENT_SCAN_RESULTS:
wpa_supplicant_event_scan_results(wpa_s);
break;
case EVENT_ASSOCINFO:
wpa_supplicant_event_associnfo(wpa_s, data);
break;
case EVENT_INTERFACE_STATUS:
wpa_supplicant_event_interface_status(wpa_s, data);
break;
case EVENT_PMKID_CANDIDATE:
wpa_supplicant_event_pmkid_candidate(wpa_s, data);
break;
default:
wpa_printf(MSG_INFO, "Unknown event %d", event);
break;
}
}

View file

@ -0,0 +1,13 @@
# IEEE 802.1X with dynamic WEP keys using EAP-PEAP/MSCHAPv2
ctrl_interface=/var/run/wpa_supplicant
network={
ssid="example 802.1x network"
key_mgmt=IEEE8021X
eap=PEAP
phase2="auth=MSCHAPV2"
identity="user name"
password="password"
ca_cert="/etc/cert/ca.pem"
}

View file

@ -0,0 +1,8 @@
# Plaintext (no encryption) network
ctrl_interface=/var/run/wpa_supplicant
network={
ssid="example open network"
key_mgmt=NONE
}

View file

@ -0,0 +1,11 @@
# Static WEP keys
ctrl_interface=/var/run/wpa_supplicant
network={
ssid="example wep network"
key_mgmt=NONE
wep_key0="abcde"
wep_key1=0102030405
wep_tx_keyidx=0
}

View file

@ -0,0 +1,12 @@
# WPA-PSK/TKIP
ctrl_interface=/var/run/wpa_supplicant
network={
ssid="example wpa-psk network"
key_mgmt=WPA-PSK
proto=WPA
pairwise=TKIP
group=TKIP
psk="secret passphrase"
}

View file

@ -0,0 +1,15 @@
# WPA2-EAP/CCMP using EAP-TLS
ctrl_interface=/var/run/wpa_supplicant
network={
ssid="example wpa2-eap network"
key_mgmt=WPA-EAP
proto=WPA2
pairwise=CCMP
group=CCMP
eap=TLS
ca_cert="/etc/cert/ca.pem"
private_key="/etc/cert/user.p12"
private_key_passwd="PKCS#12 passhrase"
}

View file

@ -0,0 +1,38 @@
#ifndef HOSTAPD_H
#define HOSTAPD_H
/*
* Minimal version of hostapd header files for eapol_test to build
* radiusclient.c.
*/
#include "common.h"
void hostapd_logger(void *ctx, u8 *addr, unsigned int module, int level,
char *fmt, ...) __attribute__ ((format (printf, 5, 6)));
struct hostapd_ip_addr;
const char * hostapd_ip_txt(const struct hostapd_ip_addr *addr, char *buf,
size_t buflen);;
enum {
HOSTAPD_LEVEL_DEBUG_VERBOSE = 0,
HOSTAPD_LEVEL_DEBUG = 1,
HOSTAPD_LEVEL_INFO = 2,
HOSTAPD_LEVEL_NOTICE = 3,
HOSTAPD_LEVEL_WARNING = 4
};
#ifndef BIT
#define BIT(n) (1 << (n))
#endif
#define HOSTAPD_MODULE_IEEE80211 BIT(0)
#define HOSTAPD_MODULE_IEEE8021X BIT(1)
#define HOSTAPD_MODULE_RADIUS BIT(2)
#define HOSTAPD_MODULE_WPA BIT(3)
#define HOSTAPD_MODULE_DRIVER BIT(4)
#define HOSTAPD_MODULE_IAPP BIT(5)
#endif /* HOSTAPD_H */

View file

@ -1,3 +1,23 @@
/*
* WPA Supplicant - Layer2 packet interface definition
* Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*
* This file defines an interface for layer 2 (link layer) packet sending and
* receiving. l2_packet_linux.c is one implementation for such a layer 2
* implementation using Linux packet sockets and l2_packet_pcap.c another one
* using libpcap and libdnet. When porting %wpa_supplicant to other operating
* systems, a new l2_packet implementation may need to be added.
*/
#ifndef L2_PACKET_H
#define L2_PACKET_H
@ -12,6 +32,14 @@
#define ETH_P_RSN_PREAUTH 0x88c7
#endif
/**
* struct l2_packet_data - Internal l2_packet data structure
*
* This structure is used by the l2_packet implementation to store its private
* data. Other files use a pointer to this data when calling the l2_packet
* functions, but the contents of this structure should not be used directly
* outside l2_packet implementation.
*/
struct l2_packet_data;
struct l2_ethhdr {
@ -20,15 +48,86 @@ struct l2_ethhdr {
u16 h_proto;
} __attribute__ ((packed));
/**
* l2_packet_init - Initialize l2_packet interface
* @ifname: Interface name
* @own_addr: Optional own MAC address if available from driver interface or
* %NULL if not available
* @protocol: Ethernet protocol number in host byte order
* @rx_callback: Callback function that will be called for each received packet
* @rx_callback_ctx: Callback data (ctx) for calls to rx_callback()
* @l2_hdr: 1 = include layer 2 header, 0 = do not include header
* Returns: Pointer to internal data or %NULL on failure
*
* rx_callback function will be called with src_addr pointing to the source
* address (MAC address) of the the packet. If l2_hdr is set to 0, buf
* points to len bytes of the payload after the layer 2 header and similarly,
* TX buffers start with payload. This behavior can be changed by setting
* l2_hdr=1 to include the layer 2 header in the data buffer.
*/
struct l2_packet_data * l2_packet_init(
const char *ifname, const u8 *own_addr, unsigned short protocol,
void (*rx_callback)(void *ctx, unsigned char *src_addr,
unsigned char *buf, size_t len),
void *rx_callback_ctx);
void (*rx_callback)(void *ctx, const u8 *src_addr,
const u8 *buf, size_t len),
void *rx_callback_ctx, int l2_hdr);
/**
* l2_packet_deinit - Deinitialize l2_packet interface
* @l2: Pointer to internal l2_packet data from l2_packet_init()
*/
void l2_packet_deinit(struct l2_packet_data *l2);
/**
* l2_packet_get_own_addr - Get own layer 2 address
* @l2: Pointer to internal l2_packet data from l2_packet_init()
* @addr: Buffer for the own address (6 bytes)
* Returns: 0 on success, -1 on failure
*/
int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr);
int l2_packet_send(struct l2_packet_data *l2, u8 *buf, size_t len);
void l2_packet_set_rx_l2_hdr(struct l2_packet_data *l2, int rx_l2_hdr);
/**
* l2_packet_send - Send a packet
* @l2: Pointer to internal l2_packet data from l2_packet_init()
* @dst_addr: Destination address for the packet (only used if l2_hdr == 0)
* @proto: Protocol/ethertype for the packet in host byte order (only used if
* l2_hdr == 0)
* @buf: Packet contents to be sent; including layer 2 header if l2_hdr was
* set to 1 in l2_packet_init() call. Otherwise, only the payload of the packet
* is included.
* @len: Length of the buffer (including l2 header only if l2_hdr == 1)
* Returns: >=0 on success, <0 on failure
*/
int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
const u8 *buf, size_t len);
/**
* l2_packet_get_ip_addr - Get the current IP address from the interface
* @l2: Pointer to internal l2_packet data from l2_packet_init()
* @buf: Buffer for the IP address in text format
* @len: Maximum buffer length
* Returns: 0 on success, -1 on failure
*
* This function can be used to get the current IP address from the interface
* bound to the l2_packet. This is mainly for status information and the IP
* address will be stored as an ASCII string. This function is not essential
* for %wpa_supplicant operation, so full implementation is not required.
* l2_packet implementation will need to define the function, but it can return
* -1 if the IP address information is not available.
*/
int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len);
/**
* l2_packet_notify_auth_start - Notify l2_packet about start of authentication
* @l2: Pointer to internal l2_packet data from l2_packet_init()
*
* This function is called when authentication is expected to start, e.g., when
* association has been completed, in order to prepare l2_packet implementation
* for EAPOL frames. This function is used mainly if the l2_packet code needs
* to do polling in which case it can increasing polling frequency. This can
* also be an empty function if the l2_packet implementation does not benefit
* from knowing about the starting authentication.
*/
void l2_packet_notify_auth_start(struct l2_packet_data *l2);
#endif /* L2_PACKET_H */

View file

@ -0,0 +1,250 @@
/*
* WPA Supplicant / main() function for UNIX like OSes and MinGW
* Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include "common.h"
#include "wpa_supplicant_i.h"
extern const char *wpa_supplicant_version;
extern const char *wpa_supplicant_license;
#ifndef CONFIG_NO_STDOUT_DEBUG
extern const char *wpa_supplicant_full_license;
#endif /* CONFIG_NO_STDOUT_DEBUG */
extern struct wpa_driver_ops *wpa_supplicant_drivers[];
static void usage(void)
{
int i;
printf("%s\n\n%s\n"
"usage:\n"
" wpa_supplicant [-BddehLqqvwW] [-P<pid file>] "
"[-g<global ctrl>] \\\n"
" -i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] "
"[-p<driver_param>] \\\n"
" [-N -i<ifname> -c<conf> [-C<ctrl>] [-D<driver>] "
"[-p<driver_param>] ...]\n"
"\n"
"drivers:\n",
wpa_supplicant_version, wpa_supplicant_license);
for (i = 0; wpa_supplicant_drivers[i]; i++) {
printf(" %s = %s\n",
wpa_supplicant_drivers[i]->name,
wpa_supplicant_drivers[i]->desc);
}
#ifndef CONFIG_NO_STDOUT_DEBUG
printf("options:\n"
" -B = run daemon in the background\n"
" -c = Configuration file\n"
" -C = ctrl_interface parameter (only used if -c is not)\n"
" -i = interface name\n"
" -d = increase debugging verbosity (-dd even more)\n"
" -D = driver name\n"
" -g = global ctrl_interface\n"
" -K = include keys (passwords, etc.) in debug output\n"
" -t = include timestamp in debug messages\n"
" -h = show this help text\n"
" -L = show license (GPL and BSD)\n"
" -p = driver parameters\n"
" -P = PID file\n"
" -q = decrease debugging verbosity (-qq even less)\n"
" -v = show version\n"
" -w = wait for interface to be added, if needed\n"
" -W = wait for a control interface monitor before starting\n"
" -N = start describing new interface\n");
printf("example:\n"
" wpa_supplicant -Dwext -iwlan0 -c/etc/wpa_supplicant.conf\n");
#endif /* CONFIG_NO_STDOUT_DEBUG */
}
static void license(void)
{
#ifndef CONFIG_NO_STDOUT_DEBUG
printf("%s\n\n%s\n",
wpa_supplicant_version, wpa_supplicant_full_license);
#endif /* CONFIG_NO_STDOUT_DEBUG */
}
static void wpa_supplicant_fd_workaround(void)
{
int s, i;
/* When started from pcmcia-cs scripts, wpa_supplicant might start with
* fd 0, 1, and 2 closed. This will cause some issues because many
* places in wpa_supplicant are still printing out to stdout. As a
* workaround, make sure that fd's 0, 1, and 2 are not used for other
* sockets. */
for (i = 0; i < 3; i++) {
s = open("/dev/null", O_RDWR);
if (s > 2) {
close(s);
break;
}
}
}
int main(int argc, char *argv[])
{
int c, i;
struct wpa_interface *ifaces, *iface;
int iface_count, exitcode;
struct wpa_params params;
struct wpa_global *global;
#ifdef CONFIG_NATIVE_WINDOWS
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 0), &wsaData)) {
printf("Could not find a usable WinSock.dll\n");
return -1;
}
#endif /* CONFIG_NATIVE_WINDOWS */
memset(&params, 0, sizeof(params));
params.wpa_debug_level = MSG_INFO;
iface = ifaces = malloc(sizeof(struct wpa_interface));
if (ifaces == NULL)
return -1;
memset(iface, 0, sizeof(*iface));
iface_count = 1;
wpa_supplicant_fd_workaround();
for (;;) {
c = getopt(argc, argv, "Bc:C:D:dg:hi:KLNp:P:qtvwW");
if (c < 0)
break;
switch (c) {
case 'B':
params.daemonize++;
break;
case 'c':
iface->confname = optarg;
break;
case 'C':
iface->ctrl_interface = optarg;
break;
case 'D':
iface->driver = optarg;
break;
case 'd':
#ifdef CONFIG_NO_STDOUT_DEBUG
printf("Debugging disabled with "
"CONFIG_NO_STDOUT_DEBUG=y build time "
"option.\n");
return -1;
#else /* CONFIG_NO_STDOUT_DEBUG */
params.wpa_debug_level--;
break;
#endif /* CONFIG_NO_STDOUT_DEBUG */
case 'g':
params.ctrl_interface = optarg;
break;
case 'h':
usage();
return -1;
case 'i':
iface->ifname = optarg;
break;
case 'K':
params.wpa_debug_show_keys++;
break;
case 'L':
license();
return -1;
case 'p':
iface->driver_param = optarg;
break;
case 'P':
params.pid_file = rel2abs_path(optarg);
break;
case 'q':
params.wpa_debug_level++;
break;
case 't':
params.wpa_debug_timestamp++;
break;
case 'v':
printf("%s\n", wpa_supplicant_version);
return -1;
case 'w':
params.wait_for_interface++;
break;
case 'W':
params.wait_for_monitor++;
break;
case 'N':
iface_count++;
iface = realloc(ifaces, iface_count *
sizeof(struct wpa_interface));
if (iface == NULL) {
free(ifaces);
return -1;
}
ifaces = iface;
iface = &ifaces[iface_count - 1];
memset(iface, 0, sizeof(*iface));
break;
default:
usage();
return -1;
}
}
exitcode = 0;
global = wpa_supplicant_init(&params);
if (global == NULL) {
printf("Failed to initialize wpa_supplicant\n");
exitcode = -1;
}
for (i = 0; exitcode == 0 && i < iface_count; i++) {
if ((ifaces[i].confname == NULL &&
ifaces[i].ctrl_interface == NULL) ||
ifaces[i].ifname == NULL) {
if (iface_count == 1 && params.ctrl_interface)
break;
usage();
return -1;
}
if (wpa_supplicant_add_iface(global, &ifaces[i]) == NULL)
exitcode = -1;
}
if (exitcode == 0)
exitcode = wpa_supplicant_run(global);
wpa_supplicant_deinit(global);
free(ifaces);
free(params.pid_file);
#ifdef CONFIG_NATIVE_WINDOWS
WSACleanup();
#endif /* CONFIG_NATIVE_WINDOWS */
return exitcode;
}

View file

@ -1,6 +1,6 @@
/*
* MD5 hash implementation and interface functions
* Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
* Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -18,36 +18,38 @@
#include "common.h"
#include "md5.h"
#include "crypto.h"
void md5_mac(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
u8 *mac)
{
MD5_CTX context;
MD5Init(&context);
MD5Update(&context, key, key_len);
MD5Update(&context, data, data_len);
MD5Update(&context, key, key_len);
MD5Final(mac, &context);
}
/* HMAC code is based on RFC 2104 */
/**
* hmac_md5_vector - HMAC-MD5 over data vector (RFC 2104)
* @key: Key for HMAC operations
* @key_len: Length of the key in bytes
* @num_elem: Number of elements in the data vector
* @addr: Pointers to the data areas
* @len: Lengths of the data blocks
* @mac: Buffer for the hash (16 bytes)
*/
void hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac)
{
MD5_CTX context;
u8 k_ipad[65]; /* inner padding - key XORd with ipad */
u8 k_opad[65]; /* outer padding - key XORd with opad */
u8 k_pad[64]; /* padding - key XORd with ipad/opad */
u8 tk[16];
int i;
const u8 *_addr[6];
size_t _len[6];
if (num_elem > 5) {
/*
* Fixed limit on the number of fragments to avoid having to
* allocate memory (which could fail).
*/
return;
}
/* if key is longer than 64 bytes reset it to key = MD5(key) */
if (key_len > 64) {
MD5Init(&context);
MD5Update(&context, key, key_len);
MD5Final(tk, &context);
md5_vector(1, &key, &key_len, tk);
key = tk;
key_len = 16;
}
@ -61,35 +63,46 @@ void hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
* opad is the byte 0x5c repeated 64 times
* and text is the data being protected */
/* start out by storing key in pads */
memset(k_ipad, 0, sizeof(k_ipad));
memset(k_opad, 0, sizeof(k_opad));
memcpy(k_ipad, key, key_len);
memcpy(k_opad, key, key_len);
/* start out by storing key in ipad */
memset(k_pad, 0, sizeof(k_pad));
memcpy(k_pad, key, key_len);
/* XOR key with ipad and opad values */
for (i = 0; i < 64; i++) {
k_ipad[i] ^= 0x36;
k_opad[i] ^= 0x5c;
}
/* XOR key with ipad values */
for (i = 0; i < 64; i++)
k_pad[i] ^= 0x36;
/* perform inner MD5 */
MD5Init(&context); /* init context for 1st pass */
MD5Update(&context, k_ipad, 64); /* start with inner pad */
/* then text of datagram; all fragments */
_addr[0] = k_pad;
_len[0] = 64;
for (i = 0; i < num_elem; i++) {
MD5Update(&context, addr[i], len[i]);
_addr[i + 1] = addr[i];
_len[i + 1] = len[i];
}
MD5Final(mac, &context); /* finish up 1st pass */
md5_vector(1 + num_elem, _addr, _len, mac);
memset(k_pad, 0, sizeof(k_pad));
memcpy(k_pad, key, key_len);
/* XOR key with opad values */
for (i = 0; i < 64; i++)
k_pad[i] ^= 0x5c;
/* perform outer MD5 */
MD5Init(&context); /* init context for 2nd pass */
MD5Update(&context, k_opad, 64); /* start with outer pad */
MD5Update(&context, mac, 16); /* then results of 1st hash */
MD5Final(mac, &context); /* finish up 2nd pass */
_addr[0] = k_pad;
_len[0] = 64;
_addr[1] = mac;
_len[1] = MD5_MAC_LEN;
md5_vector(2, _addr, _len, mac);
}
/**
* hmac_md5 - HMAC-MD5 over data buffer (RFC 2104)
* @key: Key for HMAC operations
* @key_len: Length of the key in bytes
* @data: Pointers to the data area
* @data_len: Length of the data area
* @mac: Buffer for the hash (16 bytes)
*/
void hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
u8 *mac)
{
@ -99,6 +112,40 @@ void hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
#ifndef EAP_TLS_FUNCS
struct MD5Context {
u32 buf[4];
u32 bits[2];
u8 in[64];
};
static void MD5Init(struct MD5Context *context);
static void MD5Update(struct MD5Context *context, unsigned char const *buf,
unsigned len);
static void MD5Final(unsigned char digest[16], struct MD5Context *context);
static void MD5Transform(u32 buf[4], u32 const in[16]);
typedef struct MD5Context MD5_CTX;
/**
* md5_vector - MD5 hash for data vector
* @num_elem: Number of elements in the data vector
* @addr: Pointers to the data areas
* @len: Lengths of the data blocks
* @mac: Buffer for the hash
*/
void md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
MD5_CTX ctx;
int i;
MD5Init(&ctx);
for (i = 0; i < num_elem; i++)
MD5Update(&ctx, addr[i], len[i]);
MD5Final(mac, &ctx);
}
/* ===== start - public domain MD5 implementation ===== */
/*
* This code implements the MD5 message-digest algorithm.
@ -120,13 +167,10 @@ void hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
#ifndef WORDS_BIGENDIAN
#define byteReverse(buf, len) /* Nothing */
#else
void byteReverse(unsigned char *buf, unsigned longs);
#ifndef ASM_MD5
/*
* Note: this code is harmless on little-endian machines.
*/
void byteReverse(unsigned char *buf, unsigned longs)
static void byteReverse(unsigned char *buf, unsigned longs)
{
u32 t;
do {
@ -137,13 +181,12 @@ void byteReverse(unsigned char *buf, unsigned longs)
} while (--longs);
}
#endif
#endif
/*
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
* initialization constants.
*/
void MD5Init(struct MD5Context *ctx)
static void MD5Init(struct MD5Context *ctx)
{
ctx->buf[0] = 0x67452301;
ctx->buf[1] = 0xefcdab89;
@ -158,7 +201,8 @@ void MD5Init(struct MD5Context *ctx)
* Update context to reflect the concatenation of another buffer full
* of bytes.
*/
void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
static void MD5Update(struct MD5Context *ctx, unsigned char const *buf,
unsigned len)
{
u32 t;
@ -206,7 +250,7 @@ void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
* Final wrapup - pad to 64-byte boundary with the bit pattern
* 1 0* (64-bit count of bits processed, MSB-first)
*/
void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
static void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
{
unsigned count;
unsigned char *p;
@ -247,8 +291,6 @@ void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
}
#ifndef ASM_MD5
/* The four core functions - F1 is optimized somewhat */
/* #define F1(x, y, z) (x & y | ~x & z) */
@ -266,7 +308,7 @@ void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
* reflect the addition of 16 longwords of new data. MD5Update blocks
* the data and converts bytes into longwords for this routine.
*/
void MD5Transform(u32 buf[4], u32 const in[16])
static void MD5Transform(u32 buf[4], u32 const in[16])
{
register u32 a, b, c, d;
@ -348,8 +390,6 @@ void MD5Transform(u32 buf[4], u32 const in[16])
buf[2] += c;
buf[3] += d;
}
#endif
/* ===== end - public domain MD5 implementation ===== */
#endif /* !EAP_TLS_FUNCS */

View file

@ -1,40 +1,22 @@
/*
* MD5 hash implementation and interface functions
* Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef MD5_H
#define MD5_H
#ifdef EAP_TLS_FUNCS
#include <openssl/md5.h>
#define MD5Init MD5_Init
#define MD5Update MD5_Update
#define MD5Final MD5_Final
#define MD5Transform MD5_Transform
#define MD5_MAC_LEN MD5_DIGEST_LENGTH
#else /* EAP_TLS_FUNCS */
#define MD5_MAC_LEN 16
struct MD5Context {
u32 buf[4];
u32 bits[2];
u8 in[64];
};
void MD5Init(struct MD5Context *context);
void MD5Update(struct MD5Context *context, unsigned char const *buf,
unsigned len);
void MD5Final(unsigned char digest[16], struct MD5Context *context);
void MD5Transform(u32 buf[4], u32 const in[16]);
typedef struct MD5Context MD5_CTX;
#endif /* EAP_TLS_FUNCS */
void md5_mac(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
u8 *mac);
void hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac);
void hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,

View file

@ -20,10 +20,19 @@
#include "sha1.h"
#include "ms_funcs.h"
#include "crypto.h"
#include "rc4.h"
static void challenge_hash(u8 *peer_challenge, u8 *auth_challenge,
u8 *username, size_t username_len,
/**
* challenge_hash - ChallengeHash() - RFC 2759, Sect. 8.2
* @peer_challenge: 16-octet PeerChallenge (IN)
* @auth_challenge: 16-octet AuthChallenge (IN)
* @username: 0-to-256-char UserName (IN)
* @username_len: Length of username
* @challenge: 8-octet Challenge (OUT)
*/
static void challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
const u8 *username, size_t username_len,
u8 *challenge)
{
u8 hash[SHA1_MAC_LEN];
@ -42,10 +51,18 @@ static void challenge_hash(u8 *peer_challenge, u8 *auth_challenge,
}
void nt_password_hash(u8 *password, size_t password_len, u8 *password_hash)
/**
* nt_password_hash - NtPasswordHash() - RFC 2759, Sect. 8.3
* @password: 0-to-256-unicode-char Password (IN)
* @password_len: Length of password
* @password_hash: 16-octet PasswordHash (OUT)
*/
void nt_password_hash(const u8 *password, size_t password_len,
u8 *password_hash)
{
u8 *buf;
int i;
size_t len;
/* Convert password into unicode */
buf = malloc(password_len * 2);
@ -55,18 +72,32 @@ void nt_password_hash(u8 *password, size_t password_len, u8 *password_hash)
for (i = 0; i < password_len; i++)
buf[2 * i] = password[i];
md4(buf, password_len * 2, password_hash);
len = password_len * 2;
md4_vector(1, (const u8 **) &buf, &len, password_hash);
free(buf);
}
void hash_nt_password_hash(u8 *password_hash, u8 *password_hash_hash)
/**
* hash_nt_password_hash - HashNtPasswordHash() - RFC 2759, Sect. 8.4
* @password_hash: 16-octet PasswordHash (IN)
* @password_hash_hash: 16-octet PaswordHashHash (OUT)
*/
void hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash)
{
md4(password_hash, 16, password_hash_hash);
size_t len = 16;
md4_vector(1, &password_hash, &len, password_hash_hash);
}
void challenge_response(u8 *challenge, u8 *password_hash, u8 *response)
/**
* challenge_response - ChallengeResponse() - RFC 2759, Sect. 8.5
* @challenge: 8-octet Challenge (IN)
* @password_hash: 16-octet PasswordHash (IN)
* @response: 24-octet Response (OUT)
*/
void challenge_response(const u8 *challenge, const u8 *password_hash,
u8 *response)
{
u8 zpwd[7];
des_encrypt(challenge, password_hash, response);
@ -78,9 +109,19 @@ void challenge_response(u8 *challenge, u8 *password_hash, u8 *response)
}
void generate_nt_response(u8 *auth_challenge, u8 *peer_challenge,
u8 *username, size_t username_len,
u8 *password, size_t password_len,
/**
* generate_nt_response - GenerateNTResponse() - RFC 2759, Sect. 8.1
* @auth_challenge: 16-octet AuthenticatorChallenge (IN)
* @peer_hallenge: 16-octet PeerChallenge (IN)
* @username: 0-to-256-char UserName (IN)
* @username_len: Length of username
* @password: 0-to-256-unicode-char Password (IN)
* @password_len: Length of password
* @response: 24-octet Response (OUT)
*/
void generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge,
const u8 *username, size_t username_len,
const u8 *password, size_t password_len,
u8 *response)
{
u8 challenge[8];
@ -93,11 +134,22 @@ void generate_nt_response(u8 *auth_challenge, u8 *peer_challenge,
}
void generate_authenticator_response(u8 *password, size_t password_len,
u8 *peer_challenge,
u8 *auth_challenge,
u8 *username, size_t username_len,
u8 *nt_response, u8 *response)
/**
* generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
* @password: 0-to-256-unicode-char Password (IN)
* @password_len: Length of password
* @nt_response: 24-octet NT-Response (IN)
* @peer_challenge: 16-octet PeerChallenge (IN)
* @auth_challenge: 16-octet AuthenticatorChallenge (IN)
* @username: 0-to-256-char UserName (IN)
* @username_len: Length of username
* @response: 42-octet AuthenticatorResponse (OUT)
*/
void generate_authenticator_response(const u8 *password, size_t password_len,
const u8 *peer_challenge,
const u8 *auth_challenge,
const u8 *username, size_t username_len,
const u8 *nt_response, u8 *response)
{
static const u8 magic1[39] = {
0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
@ -137,8 +189,15 @@ void generate_authenticator_response(u8 *password, size_t password_len,
}
void nt_challenge_response(u8 *challenge, u8 *password, size_t password_len,
u8 *response)
/**
* nt_challenge_response - NtChallengeResponse() - RFC 2433, Sect. A.5
* @challenge: 8-octet Challenge (IN)
* @password: 0-to-256-unicode-char Password (IN)
* @password_len: Length of password
* @response: 24-octet Response (OUT)
*/
void nt_challenge_response(const u8 *challenge, const u8 *password,
size_t password_len, u8 *response)
{
u8 password_hash[16];
nt_password_hash(password, password_len, password_hash);
@ -146,8 +205,12 @@ void nt_challenge_response(u8 *challenge, u8 *password, size_t password_len,
}
/* IN: 16-octet password_hash_hash and 24-octet nt_response
* OUT: 16-octet master_key */
/**
* get_master_key - GetMasterKey() - RFC 3079, Sect. 3.4
* @password_hash_hash: 16-octet PasswordHashHash (IN)
* @nt_response: 24-octet NTResponse (IN)
* @master_key: 16-octet MasterKey (OUT)
*/
void get_master_key(const u8 *password_hash_hash, const u8 *nt_response,
u8 *master_key)
{
@ -169,6 +232,14 @@ void get_master_key(const u8 *password_hash_hash, const u8 *nt_response,
}
/**
* get_asymetric_start_key - GetAsymetricStartKey() - RFC 3079, Sect. 3.4
* @master_key: 16-octet MasterKey (IN)
* @session_key: 8-to-16 octet SessionKey (OUT)
* @session_key_len: SessionKeyLength (Length of session_key)
* @is_send: IsSend (IN, BOOLEAN)
* @is_server: IsServer (IN, BOOLEAN)
*/
void get_asymetric_start_key(const u8 *master_key, u8 *session_key,
size_t session_key_len, int is_send,
int is_server)
@ -229,7 +300,98 @@ void get_asymetric_start_key(const u8 *master_key, u8 *session_key,
}
#define PWBLOCK_LEN 516
/**
* encrypt_pw_block_with_password_hash - EncryptPwBlobkWithPasswordHash() - RFC 2759, Sect. 8.10
* @password: 0-to-256-unicode-char Password (IN)
* @password_len: Length of password
* @password_hash: 16-octet PasswordHash (IN)
* @pw_block: 516-byte PwBlock (OUT)
*/
static void encrypt_pw_block_with_password_hash(
const u8 *password, size_t password_len,
const u8 *password_hash, u8 *pw_block)
{
size_t i, offset;
u8 *pos;
if (password_len > 256)
return;
memset(pw_block, 0, PWBLOCK_LEN);
offset = (256 - password_len) * 2;
for (i = 0; i < password_len; i++)
pw_block[offset + i * 2] = password[i];
pos = &pw_block[2 * 256];
WPA_PUT_LE16(pos, password_len * 2);
rc4(pw_block, PWBLOCK_LEN, password_hash, 16);
}
/**
* new_password_encrypted_with_old_nt_password_hash - NewPasswordEncryptedWithOldNtPasswordHash() - RFC 2759, Sect. 8.9
* @new_password: 0-to-256-unicode-char NewPassword (IN)
* @new_password_len: Length of new_password
* @old_password: 0-to-256-unicode-char OldPassword (IN)
* @old_password_len: Length of old_password
* @encrypted_pw_block: 516-octet EncryptedPwBlock (OUT)
*/
void new_password_encrypted_with_old_nt_password_hash(
const u8 *new_password, size_t new_password_len,
const u8 *old_password, size_t old_password_len,
u8 *encrypted_pw_block)
{
u8 password_hash[16];
nt_password_hash(old_password, old_password_len, password_hash);
encrypt_pw_block_with_password_hash(new_password, new_password_len,
password_hash, encrypted_pw_block);
}
/**
* nt_password_hash_encrypted_with_block - NtPasswordHashEncryptedWithBlock() - RFC 2759, Sect 8.13
* @password_hash: 16-octer PasswordHash (IN)
* @block: 16-octet Block (IN)
* @cypher: 16-octer Cypher (OUT)
*/
static void nt_password_hash_encrypted_with_block(const u8 *password_hash,
const u8 *block,
u8 *cypher)
{
des_encrypt(password_hash, block, cypher);
des_encrypt(password_hash + 8, block + 7, cypher + 8);
}
/**
* old_nt_password_hash_encrypted_with_new_nt_password_hash - OldNtPasswordHashEncryptedWithNewNtPasswordHash() - RFC 2759, Sect. 8.12
* @new_password: 0-to-256-unicode-char NewPassword (IN)
* @new_password_len: Length of new_password
* @old_password: 0-to-256-unicode-char OldPassword (IN)
* @old_password_len: Length of old_password
* @encrypted_password_ash: 16-octet EncryptedPasswordHash (OUT)
*/
void old_nt_password_hash_encrypted_with_new_nt_password_hash(
const u8 *new_password, size_t new_password_len,
const u8 *old_password, size_t old_password_len,
u8 *encrypted_password_hash)
{
u8 old_password_hash[16], new_password_hash[16];
nt_password_hash(old_password, old_password_len, old_password_hash);
nt_password_hash(new_password, new_password_len, new_password_hash);
nt_password_hash_encrypted_with_block(old_password_hash,
new_password_hash,
encrypted_password_hash);
}
#ifdef TEST_MAIN_MS_FUNCS
#include "rc4.c"
int main(int argc, char *argv[])
{
/* Test vector from RFC2759 example */

View file

@ -1,25 +1,50 @@
/*
* WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
* Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef MS_FUNCS_H
#define MS_FUNCS_H
void generate_nt_response(u8 *auth_challenge, u8 *peer_challenge,
u8 *username, size_t username_len,
u8 *password, size_t password_len,
void generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge,
const u8 *username, size_t username_len,
const u8 *password, size_t password_len,
u8 *response);
void generate_authenticator_response(u8 *password, size_t password_len,
u8 *peer_challenge,
u8 *auth_challenge,
u8 *username, size_t username_len,
u8 *nt_response, u8 *response);
void nt_challenge_response(u8 *challenge, u8 *password, size_t password_len,
u8 *response);
void generate_authenticator_response(const u8 *password, size_t password_len,
const u8 *peer_challenge,
const u8 *auth_challenge,
const u8 *username, size_t username_len,
const u8 *nt_response, u8 *response);
void nt_challenge_response(const u8 *challenge, const u8 *password,
size_t password_len, u8 *response);
void challenge_response(u8 *challenge, u8 *password_hash, u8 *response);
void nt_password_hash(u8 *password, size_t password_len, u8 *password_hash);
void hash_nt_password_hash(u8 *password_hash, u8 *password_hash_hash);
void challenge_response(const u8 *challenge, const u8 *password_hash,
u8 *response);
void nt_password_hash(const u8 *password, size_t password_len,
u8 *password_hash);
void hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash);
void get_master_key(const u8 *password_hash_hash, const u8 *nt_response,
u8 *master_key);
void get_asymetric_start_key(const u8 *master_key, u8 *session_key,
size_t session_key_len, int is_send,
int is_server);
void new_password_encrypted_with_old_nt_password_hash(
const u8 *new_password, size_t new_password_len,
const u8 *old_password, size_t old_password_len,
u8 *encrypted_pw_block);
void old_nt_password_hash_encrypted_with_new_nt_password_hash(
const u8 *new_password, size_t new_password_len,
const u8 *old_password, size_t old_password_len,
u8 *encrypted_password_hash);
#endif /* MS_FUNCS_H */

View file

@ -1,166 +1,429 @@
This is a quick hack for testing EAP-FAST with openssl.
Addition of TLS extensions to ClientHello/ServerHello is more or less
ok, though not very clean in the way that the caller needs to take
care of constructing set of all extensions. In addition there is not
mechanism for reading the TLS extensions, i.e., this would not be
enough for EAP-FAST authenticator.
Rest of the changes are obviously ugly and/or incorrect for most
parts, but it demonstrates the minimum set of changes to skip some of
the error cases that prevented completion of TLS handshake without
certificates. In other words, this is just a proof-of-concept type of
example to make it possible to experiment with EAP-FAST. Cleaner patch
for the needed functionality would be welcome..
This patch is adding support for TLS hello extensions and externally
generated pre-shared key material to OpenSSL 0.9.8. This is
based on the patch from Alexey Kobozev <akobozev@cisco.com>
(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
diff -upr openssl-0.9.7e.orig/include/openssl/ssl.h openssl-0.9.7e/include/openssl/ssl.h
--- openssl-0.9.7e.orig/include/openssl/ssl.h 2004-07-27 11:28:49.000000000 -0700
+++ openssl-0.9.7e/include/openssl/ssl.h 2004-12-24 20:29:01.000000000 -0800
@@ -929,6 +929,11 @@ struct ssl_st
diff -uprN openssl-0.9.8.orig/include/openssl/ssl.h openssl-0.9.8/include/openssl/ssl.h
--- openssl-0.9.8.orig/include/openssl/ssl.h 2005-06-10 12:51:16.000000000 -0700
+++ openssl-0.9.8/include/openssl/ssl.h 2005-07-19 20:02:15.000000000 -0700
@@ -340,6 +340,7 @@ extern "C" {
* 'struct ssl_st *' function parameters used to prototype callbacks
* in SSL_CTX. */
typedef struct ssl_st *ssl_crock_st;
+typedef struct tls_extension_st TLS_EXTENSION;
/* used to hold info on the particular ciphers used */
typedef struct ssl_cipher_st
@@ -361,6 +362,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
typedef struct ssl_st SSL;
typedef struct ssl_ctx_st SSL_CTX;
+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
+
/* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
typedef struct ssl_method_st
{
@@ -968,6 +971,15 @@ struct ssl_st
int first_packet;
int client_version; /* what was passed, used for
* SSLv3/TLS rollback check */
+
+ /* Optional ClientHello/ServerHello extension to be added to the end
+ * of the SSLv3/TLS hello message. */
+ char *hello_extension;
+ int hello_extension_len;
+ /* TLS externsions */
+ TLS_EXTENSION *tls_extension;
+ int (*tls_extension_cb)(SSL *s, TLS_EXTENSION *tls_ext, void *arg);
+ void *tls_extension_cb_arg;
+
+ /* TLS pre-shared secret session resumption */
+ tls_session_secret_cb_fn tls_session_secret_cb;
+ void *tls_session_secret_cb_arg;
};
#ifdef __cplusplus
diff -upr openssl-0.9.7e.orig/ssl/s3_both.c openssl-0.9.7e/ssl/s3_both.c
--- openssl-0.9.7e.orig/ssl/s3_both.c 2003-02-12 09:05:17.000000000 -0800
+++ openssl-0.9.7e/ssl/s3_both.c 2004-12-31 21:18:15.556846272 -0800
@@ -199,6 +199,12 @@ int ssl3_get_finished(SSL *s, int a, int
64, /* should actually be 36+4 :-) */
&ok);
@@ -1533,6 +1545,13 @@ void *SSL_COMP_get_compression_methods(v
int SSL_COMP_add_compression_method(int id,void *cm);
#endif
+ if (!ok && s->hello_extension)
+ {
+ /* Quick hack to test EAP-FAST. */
+ return(1);
+ }
+/* TLS extensions functions */
+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len);
+int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg);
+
if (!ok) return((int)n);
+/* Pre-shared secret session resumption functions */
+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
+
/* BEGIN ERROR CODES */
/* The following lines are auto generated by the script mkerr.pl. Any changes
* made after this point may be overwritten when the script is next run.
@@ -1714,6 +1733,7 @@ void ERR_load_SSL_strings(void);
#define SSL_F_TLS1_ENC 210
#define SSL_F_TLS1_SETUP_KEY_BLOCK 211
#define SSL_F_WRITE_PENDING 212
+#define SSL_F_SSL_SET_HELLO_EXTENSION 213
/* If this occurs, we have missed a message */
diff -upr openssl-0.9.7e.orig/ssl/s3_clnt.c openssl-0.9.7e/ssl/s3_clnt.c
--- openssl-0.9.7e.orig/ssl/s3_clnt.c 2004-05-15 09:39:22.000000000 -0700
+++ openssl-0.9.7e/ssl/s3_clnt.c 2004-12-31 21:16:38.617583280 -0800
@@ -588,6 +588,12 @@ static int ssl3_client_hello(SSL *s)
*(p++)=comp->id;
/* Reason codes. */
#define SSL_R_APP_DATA_IN_HANDSHAKE 100
diff -uprN openssl-0.9.8.orig/include/openssl/tls1.h openssl-0.9.8/include/openssl/tls1.h
--- openssl-0.9.8.orig/include/openssl/tls1.h 2003-07-22 05:34:21.000000000 -0700
+++ openssl-0.9.8/include/openssl/tls1.h 2005-07-19 20:02:15.000000000 -0700
@@ -282,6 +282,14 @@ extern "C" {
#define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/
#endif
+/* TLS extension struct */
+struct tls_extension_st
+{
+ unsigned short type;
+ unsigned short length;
+ void *data;
+};
+
#ifdef __cplusplus
}
#endif
diff -uprN openssl-0.9.8.orig/ssl/Makefile openssl-0.9.8/ssl/Makefile
--- openssl-0.9.8.orig/ssl/Makefile 2005-05-30 16:20:30.000000000 -0700
+++ openssl-0.9.8/ssl/Makefile 2005-07-19 20:02:15.000000000 -0700
@@ -24,7 +24,7 @@ LIBSRC= \
s2_meth.c s2_srvr.c s2_clnt.c s2_lib.c s2_enc.c s2_pkt.c \
s3_meth.c s3_srvr.c s3_clnt.c s3_lib.c s3_enc.c s3_pkt.c s3_both.c \
s23_meth.c s23_srvr.c s23_clnt.c s23_lib.c s23_pkt.c \
- t1_meth.c t1_srvr.c t1_clnt.c t1_lib.c t1_enc.c \
+ t1_meth.c t1_srvr.c t1_clnt.c t1_lib.c t1_enc.c t1_ext.c \
d1_meth.c d1_srvr.c d1_clnt.c d1_lib.c d1_pkt.c \
d1_both.c d1_enc.c \
ssl_lib.c ssl_err2.c ssl_cert.c ssl_sess.c \
@@ -35,7 +35,7 @@ LIBOBJ= \
s2_meth.o s2_srvr.o s2_clnt.o s2_lib.o s2_enc.o s2_pkt.o \
s3_meth.o s3_srvr.o s3_clnt.o s3_lib.o s3_enc.o s3_pkt.o s3_both.o \
s23_meth.o s23_srvr.o s23_clnt.o s23_lib.o s23_pkt.o \
- t1_meth.o t1_srvr.o t1_clnt.o t1_lib.o t1_enc.o \
+ t1_meth.o t1_srvr.o t1_clnt.o t1_lib.o t1_enc.o t1_ext.o \
d1_meth.o d1_srvr.o d1_clnt.o d1_lib.o d1_pkt.o \
d1_both.o d1_enc.o \
ssl_lib.o ssl_err2.o ssl_cert.o ssl_sess.o \
@@ -968,3 +968,4 @@ t1_srvr.o: ../include/openssl/ssl23.h ..
t1_srvr.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
t1_srvr.o: ../include/openssl/tls1.h ../include/openssl/x509.h
t1_srvr.o: ../include/openssl/x509_vfy.h ssl_locl.h t1_srvr.c
+t1_ext.o: t1_ext.c ssl_locl.h
diff -uprN openssl-0.9.8.orig/ssl/s3_clnt.c openssl-0.9.8/ssl/s3_clnt.c
--- openssl-0.9.8.orig/ssl/s3_clnt.c 2005-05-16 03:11:03.000000000 -0700
+++ openssl-0.9.8/ssl/s3_clnt.c 2005-07-19 20:02:15.000000000 -0700
@@ -606,6 +606,20 @@ int ssl3_client_hello(SSL *s)
}
*(p++)=0; /* Add the NULL method */
+
+ if (s->hello_extension)
+ {
+ memcpy(p,s->hello_extension,s->hello_extension_len);
+ p+=s->hello_extension_len;
+ }
+ /* send client hello extensions if any */
+ if (s->version >= TLS1_VERSION && s->tls_extension)
+ {
+ // set the total extensions length
+ s2n(s->tls_extension->length + 4, p);
+
+ // put the extensions with type and length
+ s2n(s->tls_extension->type, p);
+ s2n(s->tls_extension->length, p);
+
+ memcpy(p, s->tls_extension->data, s->tls_extension->length);
+ p+=s->tls_extension->length;
+ }
+
l=(p-d);
d=buf;
@@ -779,6 +785,11 @@ static int ssl3_get_server_certificate(S
if (s->s3->tmp.message_type != SSL3_MT_CERTIFICATE)
{
+ if (s->hello_extension)
+ {
+ /* Quick hack to test EAP-FAST. */
+ return(1);
+ }
al=SSL_AD_UNEXPECTED_MESSAGE;
SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,SSL_R_BAD_MESSAGE_TYPE);
goto f_err;
@@ -951,6 +962,12 @@ static int ssl3_get_key_exchange(SSL *s)
DH *dh=NULL;
#endif
+ if (s->hello_extension)
+ {
+ /* Quick hack to test EAP-FAST. */
+ return(1);
+ }
+
/* use same message size as in ssl3_get_certificate_request()
* as ServerKeyExchange message may be skipped */
n=ssl3_get_message(s,
@@ -1264,6 +1281,12 @@ static int ssl3_get_certificate_request(
unsigned char *p,*d,*q;
STACK_OF(X509_NAME) *ca_sk=NULL;
+ if (s->hello_extension)
+ {
+ /* Quick hack to test EAP-FAST. */
+ return(1);
+ }
+
n=ssl3_get_message(s,
SSL3_ST_CR_CERT_REQ_A,
SSL3_ST_CR_CERT_REQ_B,
@@ -1407,6 +1430,12 @@ static int ssl3_get_server_done(SSL *s)
int ok,ret=0;
*(d++)=SSL3_MT_CLIENT_HELLO;
@@ -628,7 +642,7 @@ int ssl3_get_server_hello(SSL *s)
STACK_OF(SSL_CIPHER) *sk;
SSL_CIPHER *c;
unsigned char *p,*d;
- int i,al,ok;
+ int i,al,ok,pre_shared;
unsigned int j;
long n;
SSL_COMP *comp;
@@ -693,7 +707,24 @@ int ssl3_get_server_hello(SSL *s)
goto f_err;
}
+ if (s->hello_extension)
- if (j != 0 && j == s->session->session_id_length
+ /* check if we want to resume the session based on external pre-shared secret */
+ pre_shared = 0;
+ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
+ {
+ SSL_CIPHER *pref_cipher=NULL;
+ s->session->master_key_length=sizeof(s->session->master_key);
+ if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
+ NULL, &pref_cipher, s->tls_session_secret_cb_arg))
+ {
+ /* Quick hack to test EAP-FAST. */
+ return(1);
+ s->hit=1;
+ s->session->cipher=pref_cipher ? pref_cipher : ssl_get_cipher_by_char(s,p+j);
+ s->session->session_id_length = j;
+ memcpy(s->session->session_id, p, j);
+ pre_shared = 1;
+ }
+ }
+
n=ssl3_get_message(s,
SSL3_ST_CR_SRVR_DONE_A,
SSL3_ST_CR_SRVR_DONE_B,
@@ -1439,6 +1468,12 @@ static int ssl3_send_client_key_exchange
KSSL_ERR kssl_err;
#endif /* OPENSSL_NO_KRB5 */
+ if (s->hello_extension)
+ {
+ /* Quick hack to test EAP-FAST. */
+ return(1);
+ }
+
if (s->state == SSL3_ST_CW_KEY_EXCH_A)
{
d=(unsigned char *)s->init_buf->data;
@@ -1880,6 +1915,12 @@ static int ssl3_check_cert_and_algorithm
DH *dh;
+ if ((pre_shared || j != 0) && j == s->session->session_id_length
&& memcmp(p,s->session->session_id,j) == 0)
{
if(s->sid_ctx_length != s->session->sid_ctx_length
diff -uprN openssl-0.9.8.orig/ssl/s3_srvr.c openssl-0.9.8/ssl/s3_srvr.c
--- openssl-0.9.8.orig/ssl/s3_srvr.c 2005-05-22 17:32:55.000000000 -0700
+++ openssl-0.9.8/ssl/s3_srvr.c 2005-07-19 20:02:15.000000000 -0700
@@ -955,6 +955,75 @@ int ssl3_get_client_hello(SSL *s)
}
#endif
+ if (s->hello_extension)
+ /* Check for TLS client hello extension here */
+ if (p < (d+n) && s->version >= TLS1_VERSION)
+ {
+ if (s->tls_extension_cb)
+ {
+ /* Quick hack to test EAP-FAST. */
+ return(1);
+ }
+ TLS_EXTENSION tls_ext;
+ unsigned short ext_total_len;
+
+ n2s(p, ext_total_len);
+ n2s(p, tls_ext.type);
+ n2s(p, tls_ext.length);
+
sc=s->session->sess_cert;
+ // sanity check in TLS extension len
+ if (tls_ext.length > (d+n) - p)
+ {
+ // just cut the lenth to packet border
+ tls_ext.length = (d+n) - p;
+ }
+
+ tls_ext.data = p;
+
+ // returns an alert code or 0
+ al = s->tls_extension_cb(s, &tls_ext, s->tls_extension_cb_arg);
+ if (al != 0)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_PEER_ERROR);
+ goto f_err;
+ }
+ }
+ }
+
+ /* Check if we want to use external pre-shared secret for this handshake */
+ /* for not reused session only */
+ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
+ {
+ SSL_CIPHER *pref_cipher=NULL;
+
+ s->session->master_key_length=sizeof(s->session->master_key);
+ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
+ ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
+ {
+ s->hit=1;
+ s->session->ciphers=ciphers;
+ s->session->verify_result=X509_V_OK;
+
+ ciphers=NULL;
+
+ /* check if some cipher was preferred by call back */
+ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
+ if (pref_cipher == NULL)
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
+ goto f_err;
+ }
+
+ s->session->cipher=pref_cipher;
+
+ if (s->cipher_list)
+ sk_SSL_CIPHER_free(s->cipher_list);
+
+ if (s->cipher_list_by_id)
+ sk_SSL_CIPHER_free(s->cipher_list_by_id);
+
+ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
+ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
+ }
+ }
+
/* Given s->session->ciphers and SSL_get_ciphers, we must
* pick a cipher */
if (sc == NULL)
diff -upr openssl-0.9.7e.orig/ssl/ssl.h openssl-0.9.7e/ssl/ssl.h
--- openssl-0.9.7e.orig/ssl/ssl.h 2004-07-27 11:28:49.000000000 -0700
+++ openssl-0.9.7e/ssl/ssl.h 2004-12-24 20:29:01.000000000 -0800
@@ -929,6 +929,11 @@ struct ssl_st
diff -uprN openssl-0.9.8.orig/ssl/ssl_err.c openssl-0.9.8/ssl/ssl_err.c
--- openssl-0.9.8.orig/ssl/ssl_err.c 2005-06-10 12:51:16.000000000 -0700
+++ openssl-0.9.8/ssl/ssl_err.c 2005-07-19 20:02:15.000000000 -0700
@@ -242,6 +242,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
{ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"},
{ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"},
{ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"},
+{ERR_FUNC(SSL_F_SSL_SET_HELLO_EXTENSION), "SSL_set_hello_extension"},
{0,NULL}
};
diff -uprN openssl-0.9.8.orig/ssl/ssl.h openssl-0.9.8/ssl/ssl.h
--- openssl-0.9.8.orig/ssl/ssl.h 2005-06-10 12:51:16.000000000 -0700
+++ openssl-0.9.8/ssl/ssl.h 2005-07-19 20:02:15.000000000 -0700
@@ -340,6 +340,7 @@ extern "C" {
* 'struct ssl_st *' function parameters used to prototype callbacks
* in SSL_CTX. */
typedef struct ssl_st *ssl_crock_st;
+typedef struct tls_extension_st TLS_EXTENSION;
/* used to hold info on the particular ciphers used */
typedef struct ssl_cipher_st
@@ -361,6 +362,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
typedef struct ssl_st SSL;
typedef struct ssl_ctx_st SSL_CTX;
+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
+
/* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
typedef struct ssl_method_st
{
@@ -968,6 +971,15 @@ struct ssl_st
int first_packet;
int client_version; /* what was passed, used for
* SSLv3/TLS rollback check */
+
+ /* Optional ClientHello/ServerHello extension to be added to the end
+ * of the SSLv3/TLS hello message. */
+ char *hello_extension;
+ int hello_extension_len;
+ /* TLS externsions */
+ TLS_EXTENSION *tls_extension;
+ int (*tls_extension_cb)(SSL *s, TLS_EXTENSION *tls_ext, void *arg);
+ void *tls_extension_cb_arg;
+
+ /* TLS pre-shared secret session resumption */
+ tls_session_secret_cb_fn tls_session_secret_cb;
+ void *tls_session_secret_cb_arg;
};
#ifdef __cplusplus
diff -upr openssl-0.9.7e.orig/ssl/ssl_lib.c openssl-0.9.7e/ssl/ssl_lib.c
--- openssl-0.9.7e.orig/ssl/ssl_lib.c 2004-05-11 05:46:12.000000000 -0700
+++ openssl-0.9.7e/ssl/ssl_lib.c 2004-12-24 20:35:22.000000000 -0800
@@ -478,6 +478,7 @@ void SSL_free(SSL *s)
kssl_ctx_free(s->kssl_ctx);
#endif /* OPENSSL_NO_KRB5 */
@@ -1533,6 +1545,13 @@ void *SSL_COMP_get_compression_methods(v
int SSL_COMP_add_compression_method(int id,void *cm);
#endif
+ OPENSSL_free(s->hello_extension);
OPENSSL_free(s);
+/* TLS extensions functions */
+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len);
+int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg);
+
+/* Pre-shared secret session resumption functions */
+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
+
/* BEGIN ERROR CODES */
/* The following lines are auto generated by the script mkerr.pl. Any changes
* made after this point may be overwritten when the script is next run.
@@ -1714,6 +1733,7 @@ void ERR_load_SSL_strings(void);
#define SSL_F_TLS1_ENC 210
#define SSL_F_TLS1_SETUP_KEY_BLOCK 211
#define SSL_F_WRITE_PENDING 212
+#define SSL_F_SSL_SET_HELLO_EXTENSION 213
/* Reason codes. */
#define SSL_R_APP_DATA_IN_HANDSHAKE 100
diff -uprN openssl-0.9.8.orig/ssl/ssl_sess.c openssl-0.9.8/ssl/ssl_sess.c
--- openssl-0.9.8.orig/ssl/ssl_sess.c 2005-04-29 13:10:06.000000000 -0700
+++ openssl-0.9.8/ssl/ssl_sess.c 2005-07-19 20:02:15.000000000 -0700
@@ -656,6 +656,15 @@ long SSL_CTX_get_timeout(const SSL_CTX *
return(s->session_timeout);
}
+int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len,
+ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg)
+{
+ if (s == NULL) return(0);
+ s->tls_session_secret_cb = tls_session_secret_cb;
+ s->tls_session_secret_cb_arg = arg;
+ return(1);
+}
+
typedef struct timeout_param_st
{
SSL_CTX *ctx;
diff -uprN openssl-0.9.8.orig/ssl/t1_ext.c openssl-0.9.8/ssl/t1_ext.c
--- openssl-0.9.8.orig/ssl/t1_ext.c 1969-12-31 16:00:00.000000000 -0800
+++ openssl-0.9.8/ssl/t1_ext.c 2005-07-19 20:03:29.000000000 -0700
@@ -0,0 +1,48 @@
+
+#include <stdio.h>
+#include "ssl_locl.h"
+
+
+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len)
+{
+ if(s->version >= TLS1_VERSION)
+ {
+ if(s->tls_extension)
+ {
+ OPENSSL_free(s->tls_extension);
+ s->tls_extension = NULL;
+ }
+
+ if(ext_data)
+ {
+ s->tls_extension = OPENSSL_malloc(sizeof(TLS_EXTENSION) + ext_len);
+ if(!s->tls_extension)
+ {
+ SSLerr(SSL_F_SSL_SET_HELLO_EXTENSION, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ s->tls_extension->type = ext_type;
+ s->tls_extension->length = ext_len;
+ s->tls_extension->data = s->tls_extension + 1;
+ memcpy(s->tls_extension->data, ext_data, ext_len);
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg)
+{
+ if(s->version >= TLS1_VERSION)
+ {
+ s->tls_extension_cb = cb;
+ s->tls_extension_cb_arg = arg;
+
+ return 1;
+ }
+
+ return 0;
+}
diff -uprN openssl-0.9.8.orig/ssl/t1_lib.c openssl-0.9.8/ssl/t1_lib.c
--- openssl-0.9.8.orig/ssl/t1_lib.c 2005-04-26 09:02:40.000000000 -0700
+++ openssl-0.9.8/ssl/t1_lib.c 2005-07-19 20:02:15.000000000 -0700
@@ -131,6 +131,10 @@ int tls1_new(SSL *s)
void tls1_free(SSL *s)
{
+ if(s->tls_extension)
+ {
+ OPENSSL_free(s->tls_extension);
+ }
ssl3_free(s);
}
diff -uprN openssl-0.9.8.orig/ssl/tls1.h openssl-0.9.8/ssl/tls1.h
--- openssl-0.9.8.orig/ssl/tls1.h 2003-07-22 05:34:21.000000000 -0700
+++ openssl-0.9.8/ssl/tls1.h 2005-07-19 20:02:15.000000000 -0700
@@ -282,6 +282,14 @@ extern "C" {
#define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/
#endif
+/* TLS extension struct */
+struct tls_extension_st
+{
+ unsigned short type;
+ unsigned short length;
+ void *data;
+};
+
#ifdef __cplusplus
}
#endif
diff -uprN openssl-0.9.8.orig/util/ssleay.num openssl-0.9.8/util/ssleay.num
--- openssl-0.9.8.orig/util/ssleay.num 2005-05-08 17:22:02.000000000 -0700
+++ openssl-0.9.8/util/ssleay.num 2005-07-19 20:02:15.000000000 -0700
@@ -226,3 +226,6 @@ DTLSv1_server_method
SSL_COMP_get_compression_methods 276 EXIST:!VMS:FUNCTION:COMP
SSL_COMP_get_compress_methods 276 EXIST:VMS:FUNCTION:COMP
SSL_SESSION_get_id 277 EXIST::FUNCTION:
+SSL_set_hello_extension 278 EXIST::FUNCTION:
+SSL_set_hello_extension_cb 279 EXIST::FUNCTION:
+SSL_set_session_secret_cb 280 EXIST::FUNCTION:

View file

@ -86,8 +86,8 @@ struct scard_data {
long ctx;
long card;
unsigned long protocol;
SCARD_IO_REQUEST recv_pci;
sim_types sim_type;
int pin1_required;
};
@ -96,7 +96,7 @@ static int _scard_select_file(struct scard_data *scard, unsigned short file_id,
sim_types sim_type, unsigned char *aid);
static int scard_select_file(struct scard_data *scard, unsigned short file_id,
unsigned char *buf, size_t *buf_len);
static int scard_verify_pin(struct scard_data *scard, char *pin);
static int scard_verify_pin(struct scard_data *scard, const char *pin);
static int scard_parse_fsp_templ(unsigned char *buf, size_t buf_len,
@ -183,7 +183,7 @@ static int scard_pin_needed(struct scard_data *scard,
}
struct scard_data * scard_init(scard_sim_type sim_type, char *pin)
struct scard_data * scard_init(scard_sim_type sim_type)
{
long ret, len;
struct scard_data *scard;
@ -294,20 +294,8 @@ struct scard_data * scard_init(scard_sim_type sim_type, char *pin)
/* Verify whether CHV1 (PIN1) is needed to access the card. */
if (scard_pin_needed(scard, buf, blen)) {
scard->pin1_required = 1;
wpa_printf(MSG_DEBUG, "PIN1 needed for SIM access");
if (pin == NULL) {
wpa_printf(MSG_INFO, "No PIN configured for SIM "
"access");
/* TODO: ask PIN from user through a frontend (e.g.,
* wpa_cli) */
goto failed;
}
if (scard_verify_pin(scard, pin)) {
wpa_printf(MSG_INFO, "PIN verification failed for "
"SIM access");
/* TODO: what to do? */
goto failed;
}
}
return scard;
@ -319,6 +307,29 @@ failed:
}
int scard_set_pin(struct scard_data *scard, const char *pin)
{
if (scard == NULL)
return -1;
/* Verify whether CHV1 (PIN1) is needed to access the card. */
if (scard->pin1_required) {
if (pin == NULL) {
wpa_printf(MSG_DEBUG, "No PIN configured for SIM "
"access");
return -1;
}
if (scard_verify_pin(scard, pin)) {
wpa_printf(MSG_INFO, "PIN verification failed for "
"SIM access");
return -1;
}
}
return 0;
}
void scard_deinit(struct scard_data *scard)
{
long ret;
@ -360,7 +371,7 @@ static long scard_transmit(struct scard_data *scard,
scard->protocol == SCARD_PROTOCOL_T1 ?
SCARD_PCI_T1 : SCARD_PCI_T0,
send, (unsigned long) send_len,
&scard->recv_pci, recv, &rlen);
NULL, recv, &rlen);
*recv_len = rlen;
if (ret == SCARD_S_SUCCESS) {
wpa_hexdump(MSG_DEBUG, "SCARD: scard_transmit: recv",
@ -498,7 +509,7 @@ static int scard_read_file(struct scard_data *scard,
}
static int scard_verify_pin(struct scard_data *scard, char *pin)
static int scard_verify_pin(struct scard_data *scard, const char *pin)
{
long ret;
unsigned char resp[3];
@ -621,7 +632,7 @@ int scard_gsm_auth(struct scard_data *scard, unsigned char *rand,
memcpy(cmd + 6, rand, 16);
}
len = sizeof(resp);
ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len);
ret = scard_transmit(scard, cmd, cmdlen, resp, &len);
if (ret != SCARD_S_SUCCESS)
return -2;

View file

@ -1,3 +1,17 @@
/*
* WPA Supplicant / PC/SC smartcard interface for USIM, GSM SIM
* Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef PCSC_FUNCS_H
#define PCSC_FUNCS_H
@ -27,9 +41,10 @@ typedef enum {
#ifdef PCSC_FUNCS
struct scard_data * scard_init(scard_sim_type sim_type, char *pin);
struct scard_data * scard_init(scard_sim_type sim_type);
void scard_deinit(struct scard_data *scard);
int scard_set_pin(struct scard_data *scard, const char *pin);
int scard_get_imsi(struct scard_data *scard, char *imsi, size_t *len);
int scard_gsm_auth(struct scard_data *scard, unsigned char *rand,
unsigned char *sres, unsigned char *kc);
@ -39,8 +54,9 @@ int scard_umts_auth(struct scard_data *scard, unsigned char *rand,
#else /* PCSC_FUNCS */
#define scard_init(s, p) NULL
#define scard_init(s) NULL
#define scard_deinit(s) do { } while (0)
#define scard_set_pin(s, p) -1
#define scard_get_imsi(s, i, l) -1
#define scard_gsm_auth(s, r, s2, k) -1
#define scard_umts_auth(s, r, a, r2, rl, i, c, a2) -1

Some files were not shown because too many files have changed in this diff Show more