mirror of
https://github.com/opnsense/src.git
synced 2026-05-28 04:12:45 -04:00
Import of WPA supplicant 0.4.8
This commit is contained in:
parent
e00d94fa7c
commit
4e0922e888
156 changed files with 32587 additions and 6597 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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++;
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
198
contrib/wpa_supplicant/base64.c
Normal file
198
contrib/wpa_supplicant/base64.c
Normal 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 */
|
||||
23
contrib/wpa_supplicant/base64.h
Normal file
23
contrib/wpa_supplicant/base64.h
Normal 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 */
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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 */
|
||||
|
|
|
|||
695
contrib/wpa_supplicant/config_file.c
Normal file
695
contrib/wpa_supplicant/config_file.c
Normal 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;
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
|
|||
14
contrib/wpa_supplicant/config_types.h
Normal file
14
contrib/wpa_supplicant/config_types.h
Normal 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 */
|
||||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
163
contrib/wpa_supplicant/crypto_gnutls.c
Normal file
163
contrib/wpa_supplicant/crypto_gnutls.c
Normal 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
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
264
contrib/wpa_supplicant/doc/code_structure.doxygen
Normal file
264
contrib/wpa_supplicant/doc/code_structure.doxygen
Normal 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
|
||||
|
||||
*/
|
||||
409
contrib/wpa_supplicant/doc/ctrl_iface.doxygen
Normal file
409
contrib/wpa_supplicant/doc/ctrl_iface.doxygen
Normal 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
|
||||
|
||||
*/
|
||||
25
contrib/wpa_supplicant/doc/docbook/Makefile
Normal file
25
contrib/wpa_supplicant/doc/docbook/Makefile
Normal 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)
|
||||
84
contrib/wpa_supplicant/doc/docbook/wpa_background.8
Normal file
84
contrib/wpa_supplicant/doc/docbook/wpa_background.8
Normal 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.
|
||||
101
contrib/wpa_supplicant/doc/docbook/wpa_background.sgml
Normal file
101
contrib/wpa_supplicant/doc/docbook/wpa_background.sgml
Normal 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<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).</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>
|
||||
202
contrib/wpa_supplicant/doc/docbook/wpa_cli.8
Normal file
202
contrib/wpa_supplicant/doc/docbook/wpa_cli.8
Normal 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.
|
||||
330
contrib/wpa_supplicant/doc/docbook/wpa_cli.sgml
Normal file
330
contrib/wpa_supplicant/doc/docbook/wpa_cli.sgml
Normal 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-<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.</para>
|
||||
|
||||
<para>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.</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 <debug level></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 <BSSID></term>
|
||||
<listitem>
|
||||
<para>force preauthentication</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>identity <network id> <identity></term>
|
||||
<listitem>
|
||||
<para>configure identity for an SSID</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>password <network id> <password></term>
|
||||
<listitem>
|
||||
<para>configure password for an SSID</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>pin <network id> <pin></term>
|
||||
<listitem>
|
||||
<para>configure pin for an SSID</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>otp <network id> <password></term>
|
||||
<listitem>
|
||||
<para>configure one-time-password for an SSID</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>bssid *lt;network id> <BSSID></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>
|
||||
39
contrib/wpa_supplicant/doc/docbook/wpa_passphrase.8
Normal file
39
contrib/wpa_supplicant/doc/docbook/wpa_passphrase.8
Normal 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.
|
||||
72
contrib/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
Normal file
72
contrib/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
Normal 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>
|
||||
544
contrib/wpa_supplicant/doc/docbook/wpa_supplicant.8
Normal file
544
contrib/wpa_supplicant/doc/docbook/wpa_supplicant.8
Normal 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.
|
||||
230
contrib/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5
Normal file
230
contrib/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5
Normal 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)
|
||||
244
contrib/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml
Normal file
244
contrib/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml
Normal 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>
|
||||
761
contrib/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
Normal file
761
contrib/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
Normal 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<driver
|
||||
name> 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>
|
||||
243
contrib/wpa_supplicant/doc/doxygen.fast
Normal file
243
contrib/wpa_supplicant/doc/doxygen.fast
Normal 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
|
||||
230
contrib/wpa_supplicant/doc/doxygen.full
Normal file
230
contrib/wpa_supplicant/doc/doxygen.full
Normal 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
|
||||
180
contrib/wpa_supplicant/doc/driver_wrapper.doxygen
Normal file
180
contrib/wpa_supplicant/doc/driver_wrapper.doxygen
Normal 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)
|
||||
*/
|
||||
38
contrib/wpa_supplicant/doc/eap.doxygen
Normal file
38
contrib/wpa_supplicant/doc/eap.doxygen
Normal 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.
|
||||
*/
|
||||
129
contrib/wpa_supplicant/doc/kerneldoc2doxygen.pl
Executable file
129
contrib/wpa_supplicant/doc/kerneldoc2doxygen.pl
Executable 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 $_;
|
||||
|
||||
56
contrib/wpa_supplicant/doc/mainpage.doxygen
Normal file
56
contrib/wpa_supplicant/doc/mainpage.doxygen
Normal 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
|
||||
|
||||
*/
|
||||
121
contrib/wpa_supplicant/doc/porting.doxygen
Normal file
121
contrib/wpa_supplicant/doc/porting.doxygen
Normal 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.
|
||||
|
||||
*/
|
||||
288
contrib/wpa_supplicant/doc/testing_tools.doxygen
Normal file
288
contrib/wpa_supplicant/doc/testing_tools.doxygen
Normal 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.
|
||||
|
||||
*/
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
153
contrib/wpa_supplicant/driver_hostap.h
Normal file
153
contrib/wpa_supplicant/driver_hostap.h
Normal 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 */
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
271
contrib/wpa_supplicant/driver_wired.c
Normal file
271
contrib/wpa_supplicant/driver_wired.c
Normal 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,
|
||||
};
|
||||
|
|
@ -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
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
510
contrib/wpa_supplicant/eap_pax.c
Normal file
510
contrib/wpa_supplicant/eap_pax.c
Normal 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,
|
||||
};
|
||||
152
contrib/wpa_supplicant/eap_pax_common.c
Normal file
152
contrib/wpa_supplicant/eap_pax_common.c
Normal 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;
|
||||
}
|
||||
84
contrib/wpa_supplicant/eap_pax_common.h
Normal file
84
contrib/wpa_supplicant/eap_pax_common.h
Normal 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 */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
57
contrib/wpa_supplicant/eap_psk_common.c
Normal file
57
contrib/wpa_supplicant/eap_psk_common.c
Normal 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++;
|
||||
}
|
||||
}
|
||||
92
contrib/wpa_supplicant/eap_psk_common.h
Normal file
92
contrib/wpa_supplicant/eap_psk_common.h
Normal 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 */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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(¶ms, 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, ¶ms.ca_cert, ¶ms.ca_cert_blob,
|
||||
¶ms.ca_cert_blob_len) ||
|
||||
eap_tls_check_blob(sm, ¶ms.client_cert,
|
||||
¶ms.client_cert_blob,
|
||||
¶ms.client_cert_blob_len) ||
|
||||
eap_tls_check_blob(sm, ¶ms.private_key,
|
||||
¶ms.private_key_blob,
|
||||
¶ms.private_key_blob_len) ||
|
||||
eap_tls_check_blob(sm, ¶ms.dh_file, ¶ms.dh_blob,
|
||||
¶ms.dh_blob_len)) {
|
||||
wpa_printf(MSG_INFO, "SSL: Failed to get configuration blobs");
|
||||
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, ¶ms);
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
759
contrib/wpa_supplicant/events.c
Normal file
759
contrib/wpa_supplicant/events.c
Normal 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;
|
||||
}
|
||||
}
|
||||
13
contrib/wpa_supplicant/examples/ieee8021x.conf
Normal file
13
contrib/wpa_supplicant/examples/ieee8021x.conf
Normal 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"
|
||||
}
|
||||
8
contrib/wpa_supplicant/examples/plaintext.conf
Normal file
8
contrib/wpa_supplicant/examples/plaintext.conf
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
# Plaintext (no encryption) network
|
||||
|
||||
ctrl_interface=/var/run/wpa_supplicant
|
||||
|
||||
network={
|
||||
ssid="example open network"
|
||||
key_mgmt=NONE
|
||||
}
|
||||
11
contrib/wpa_supplicant/examples/wep.conf
Normal file
11
contrib/wpa_supplicant/examples/wep.conf
Normal 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
|
||||
}
|
||||
12
contrib/wpa_supplicant/examples/wpa-psk-tkip.conf
Normal file
12
contrib/wpa_supplicant/examples/wpa-psk-tkip.conf
Normal 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"
|
||||
}
|
||||
15
contrib/wpa_supplicant/examples/wpa2-eap-ccmp.conf
Normal file
15
contrib/wpa_supplicant/examples/wpa2-eap-ccmp.conf
Normal 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"
|
||||
}
|
||||
38
contrib/wpa_supplicant/hostapd.h
Normal file
38
contrib/wpa_supplicant/hostapd.h
Normal 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 */
|
||||
|
|
@ -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 */
|
||||
|
|
|
|||
250
contrib/wpa_supplicant/main.c
Normal file
250
contrib/wpa_supplicant/main.c
Normal 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(¶ms, 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(¶ms);
|
||||
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;
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Reference in a new issue