Import of hostapd 0.4.8
This commit is contained in:
parent
fd7895c8dd
commit
89f5e593c0
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/vendor/hostapd/dist/; revision=156373
@ -1,18 +1,102 @@
|
||||
ChangeLog for hostapd
|
||||
|
||||
2005-06-10 - v0.3.9
|
||||
2006-02-08 - v0.4.8
|
||||
* fixed stdarg use in hostapd_logger(): if both stdout and syslog
|
||||
logging was enabled, hostapd could trigger a segmentation fault in
|
||||
vsyslog on some CPU -- C library combinations
|
||||
|
||||
2005-11-20 - v0.4.7 (beginning of 0.4.x stable releases)
|
||||
* driver_wired: fixed EAPOL sending to optionally use PAE group address
|
||||
as the destination instead of supplicant MAC address; this is
|
||||
disabled by default, but should be enabled with use_pae_group_addr=1
|
||||
in configuration file if the wired interface is used by only one
|
||||
device at the time (common switch configuration)
|
||||
* driver_madwifi: configure driver to use TKIP countermeasures in order
|
||||
to get correct behavior (IEEE 802.11 association failing; previously,
|
||||
association succeeded, but hostpad forced disassociation immediately)
|
||||
* driver_madwifi: added support for madwifi-ng
|
||||
|
||||
2005-10-27 - v0.4.6
|
||||
* added support for replacing user identity from EAP with RADIUS
|
||||
User-Name attribute from Access-Accept message, if that is included,
|
||||
for the RADIUS accounting messages (e.g., for EAP-PEAP/TTLS to get
|
||||
tunneled identity into accounting messages when the RADIUS server
|
||||
does not support better way of doing this with Class attribute)
|
||||
* driver_madwifi: fixed EAPOL packet receive for configuration where
|
||||
ath# is part of a bridge interface
|
||||
* added a configuration file and log analyzer script for logwatch
|
||||
* fixed EAPOL state machine step function to process all state
|
||||
transitions before processing new events; this resolves a race
|
||||
condition in which EAPOL-Start message could trigger hostapd to send
|
||||
two EAP-Response/Identity frames to the authentication server
|
||||
|
||||
2005-09-25 - v0.4.5
|
||||
* added client CA list to the TLS certificate request in order to make
|
||||
it easier for the client to select which certificate to use
|
||||
* added experimental support for EAP-PSK
|
||||
* added support for WE-19 (hostap, madwifi)
|
||||
|
||||
2005-08-21 - v0.4.4
|
||||
* fixed build without CONFIG_RSN_PREAUTH
|
||||
* fixed FreeBSD build
|
||||
|
||||
2005-06-26 - v0.4.3
|
||||
* fixed PMKSA caching to copy User-Name and Class attributes so that
|
||||
RADIUS accounting gets correct information
|
||||
* start RADIUS accounting only after successful completion of WPA
|
||||
4-Way Handshake if WPA-PSK is used
|
||||
* fixed PMKSA caching for the case where STA (re)associates without
|
||||
first disassociating
|
||||
|
||||
2005-06-12 - v0.4.2
|
||||
* EAP-PAX is now registered as EAP type 46
|
||||
* fixed EAP-PAX MAC calculation
|
||||
* fixed EAP-PAX CK and ICK key derivation
|
||||
* renamed eap_authenticator configuration variable to eap_server to
|
||||
better match with RFC 3748 (EAP) terminology
|
||||
* driver_test: added support for testing hostapd with wpa_supplicant
|
||||
by using test driver interface without any kernel drivers or network
|
||||
cards
|
||||
|
||||
2005-05-22 - v0.4.1
|
||||
* fixed RADIUS server initialization when only auth or acct server
|
||||
is configured and the other one is left empty
|
||||
* driver_madwifi: added support for RADIUS accounting
|
||||
* driver_madwifi: added preliminary support for compiling against 'BSD'
|
||||
branch of madwifi CVS tree
|
||||
* driver_madwifi: fixed pairwise key removal to allow WPA reauth
|
||||
without disassociation
|
||||
* added support for reading additional certificates from PKCS#12 files
|
||||
and adding them to the certificate chain
|
||||
* fixed RADIUS Class attribute processing to only use Access-Accept
|
||||
packets to update Class; previously, other RADIUS authentication
|
||||
packets could have cleared Class attribute
|
||||
* added support for more than one Class attribute in RADIUS packets
|
||||
* added support for verifying certificate revocation list (CRL) when
|
||||
using integrated EAP authenticator for EAP-TLS; new hostapd.conf
|
||||
options 'check_crl'; CRL must be included in the ca_cert file for now
|
||||
|
||||
2005-04-25 - v0.4.0 (beginning of 0.4.x development releases)
|
||||
* added support for including network information into
|
||||
EAP-Request/Identity message (ASCII-0 (nul) in eap_message)
|
||||
(e.g., to implement draft-adrange-eap-network-discovery-07.txt)
|
||||
* fixed a bug which caused some RSN pre-authentication cases to use
|
||||
freed memory and potentially crash hostapd
|
||||
* fixed private key loading for cases where passphrase is not set
|
||||
* added support for sending TLS alerts and aborting authentication
|
||||
when receiving a TLS alert
|
||||
* fixed WPA2 to add PMKSA cache entry when using integrated EAP
|
||||
authenticator
|
||||
* driver_madwifi: fixed pairwise key removal to allow WPA reauth
|
||||
without disassociation
|
||||
* fixed RADIUS attribute Class processing to only use Access-Accept
|
||||
packets to update Class; previously, other RADIUS authentication
|
||||
packets could have cleared Class attribute
|
||||
* fixed PMKSA caching (EAP authentication was not skipped correctly
|
||||
with the new state machine changes from IEEE 802.1X draft)
|
||||
* added support for RADIUS over IPv6; own_ip_addr, auth_server_addr,
|
||||
and acct_server_addr can now be IPv6 addresses (CONFIG_IPV6=y needs
|
||||
to be added to .config to include IPv6 support); for RADIUS server,
|
||||
radius_server_ipv6=1 needs to be set in hostapd.conf and addresses
|
||||
in RADIUS clients file can then use IPv6 format
|
||||
* added experimental support for EAP-PAX
|
||||
* replaced hostapd control interface library (hostapd_ctrl.[ch]) with
|
||||
the same implementation that wpa_supplicant is using (wpa_ctrl.[ch])
|
||||
|
||||
2005-02-12 - v0.3.7 (beginning of 0.3.x stable releases)
|
||||
|
||||
|
@ -60,6 +60,7 @@ CFLAGS += -DCONFIG_DRIVER_BSD
|
||||
OBJS += driver_bsd.o
|
||||
CONFIG_L2_PACKET=y
|
||||
CONFIG_DNET_PCAP=y
|
||||
CONFIG_L2_FREEBSD=y
|
||||
endif
|
||||
|
||||
ifdef CONFIG_DRIVER_TEST
|
||||
@ -68,13 +69,20 @@ OBJS += driver_test.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_L2_PACKET
|
||||
OBJS += $(DIR_WPA_SUPPLICANT)/l2_packet.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_DNET_PCAP
|
||||
CFLAGS += -DUSE_DNET_PCAP
|
||||
LIBS +=-ldnet -lpcap
|
||||
ifdef CONFIG_L2_FREEBSD
|
||||
LIBS += -lpcap
|
||||
OBJS += $(DIR_WPA_SUPPLICANT)/l2_packet_freebsd.o
|
||||
else
|
||||
LIBS += -ldnet -lpcap
|
||||
OBJS += $(DIR_WPA_SUPPLICANT)/l2_packet_pcap.o
|
||||
endif
|
||||
else
|
||||
OBJS += $(DIR_WPA_SUPPLICANT)/l2_packet_linux.o
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
ifdef CONFIG_EAP_MD5
|
||||
CFLAGS += -DEAP_MD5
|
||||
@ -120,13 +128,23 @@ OBJS += eap_sim.o $(DIR_WPA_SUPPLICANT)/eap_sim_common.o
|
||||
OBJS += eap_sim_db.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_EAP_PAX
|
||||
CFLAGS += -DEAP_PAX
|
||||
OBJS += eap_pax.o $(DIR_WPA_SUPPLICANT)/eap_pax_common.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_EAP_PSK
|
||||
CFLAGS += -DEAP_PSK
|
||||
OBJS += eap_psk.o $(DIR_WPA_SUPPLICANT)/eap_psk_common.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_EAP_TLV
|
||||
CFLAGS += -DEAP_TLV
|
||||
OBJS += eap_tlv.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_EAP
|
||||
CFLAGS += -DEAP_AUTHENTICATOR
|
||||
CFLAGS += -DEAP_SERVER
|
||||
OBJS += eap.o eap_identity.o
|
||||
endif
|
||||
|
||||
@ -156,6 +174,10 @@ CFLAGS += -DRADIUS_SERVER
|
||||
OBJS += radius_server.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_IPV6
|
||||
CFLAGS += -DCONFIG_IPV6
|
||||
endif
|
||||
|
||||
ALL=hostapd hostapd_cli
|
||||
|
||||
all: verify_config $(ALL)
|
||||
@ -224,8 +246,8 @@ ifdef CONFIG_DRIVER_TEST
|
||||
endif
|
||||
echo '}' >> driver_conf.c
|
||||
|
||||
hostapd_cli: hostapd_cli.o hostapd_ctrl.o
|
||||
$(CC) -o hostapd_cli hostapd_cli.o hostapd_ctrl.o
|
||||
hostapd_cli: hostapd_cli.o $(DIR_WPA_SUPPLICANT)/wpa_ctrl.o
|
||||
$(CC) -o hostapd_cli hostapd_cli.o $(DIR_WPA_SUPPLICANT)/wpa_ctrl.o
|
||||
|
||||
clean:
|
||||
rm -f core *~ *.o hostapd hostapd_cli *.d driver_conf.c
|
||||
|
@ -2,14 +2,12 @@ hostapd - user space IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP
|
||||
Authenticator and RADIUS authentication server
|
||||
================================================================
|
||||
|
||||
Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi> and
|
||||
Copyright (c) 2002-2006, Jouni Malinen <jkmaline@cc.hut.fi> and
|
||||
contributors
|
||||
All Rights Reserved.
|
||||
|
||||
This program is dual-licensed under both the GPL version 2 and BSD
|
||||
license. Either license may be used at your option. Please note that
|
||||
some of the driver interface implementations (driver_*.c) may be
|
||||
licensed under a different license.
|
||||
license. Either license may be used at your option.
|
||||
|
||||
|
||||
|
||||
@ -77,7 +75,7 @@ and dynamic WEP keying, RADIUS accounting, WPA/WPA2 (IEEE 802.11i/RSN)
|
||||
Authenticator and dynamic TKIP/CCMP keying.
|
||||
|
||||
The current version includes support for other drivers, an integrated
|
||||
EAP authenticator (i.e., allow full authentication without requiring
|
||||
EAP server (i.e., allow full authentication without requiring
|
||||
an external RADIUS authentication server), and RADIUS authentication
|
||||
server for EAP authentication.
|
||||
|
||||
|
@ -47,6 +47,7 @@ static struct radius_msg * accounting_msg(hostapd *hapd, struct sta_info *sta,
|
||||
char buf[128];
|
||||
u8 *val;
|
||||
size_t len;
|
||||
int i;
|
||||
|
||||
msg = radius_msg_new(RADIUS_CODE_ACCOUNTING_REQUEST,
|
||||
radius_client_get_id(hapd->radius));
|
||||
@ -99,12 +100,22 @@ static struct radius_msg * accounting_msg(hostapd *hapd, struct sta_info *sta,
|
||||
}
|
||||
}
|
||||
|
||||
if (!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
|
||||
(u8 *) &hapd->conf->own_ip_addr, 4)) {
|
||||
if (hapd->conf->own_ip_addr.af == AF_INET &&
|
||||
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
|
||||
(u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
|
||||
printf("Could not add NAS-IP-Address\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IPV6
|
||||
if (hapd->conf->own_ip_addr.af == AF_INET6 &&
|
||||
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
|
||||
(u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
|
||||
printf("Could not add NAS-IPv6-Address\n");
|
||||
goto fail;
|
||||
}
|
||||
#endif /* CONFIG_IPV6 */
|
||||
|
||||
if (hapd->conf->nas_identifier &&
|
||||
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
|
||||
(u8 *) hapd->conf->nas_identifier,
|
||||
@ -150,11 +161,17 @@ static struct radius_msg * accounting_msg(hostapd *hapd, struct sta_info *sta,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
val = ieee802_1x_get_radius_class(sta->eapol_sm, &len);
|
||||
if (val &&
|
||||
!radius_msg_add_attr(msg, RADIUS_ATTR_CLASS, val, len)) {
|
||||
printf("Could not add Class\n");
|
||||
goto fail;
|
||||
for (i = 0; ; i++) {
|
||||
val = ieee802_1x_get_radius_class(sta->eapol_sm, &len,
|
||||
i);
|
||||
if (val == NULL)
|
||||
break;
|
||||
|
||||
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CLASS,
|
||||
val, len)) {
|
||||
printf("Could not add Class\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -225,7 +242,7 @@ void accounting_sta_start(hostapd *hapd, struct sta_info *sta)
|
||||
sta->acct_input_gigawords = sta->acct_output_gigawords = 0;
|
||||
hostapd_sta_clear_stats(hapd, sta->addr);
|
||||
|
||||
if (!hapd->conf->acct_server)
|
||||
if (!hapd->conf->radius->acct_server)
|
||||
return;
|
||||
|
||||
if (sta->acct_interim_interval)
|
||||
@ -250,7 +267,7 @@ void accounting_sta_report(hostapd *hapd, struct sta_info *sta, int stop)
|
||||
struct hostap_sta_driver_data data;
|
||||
u32 gigawords;
|
||||
|
||||
if (!hapd->conf->acct_server)
|
||||
if (!hapd->conf->radius->acct_server)
|
||||
return;
|
||||
|
||||
msg = accounting_msg(hapd, sta,
|
||||
@ -380,8 +397,7 @@ accounting_receive(struct radius_msg *msg, struct radius_msg *req,
|
||||
return RADIUS_RX_UNKNOWN;
|
||||
}
|
||||
|
||||
if (radius_msg_verify_acct(msg, shared_secret, shared_secret_len, req))
|
||||
{
|
||||
if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) {
|
||||
printf("Incoming RADIUS packet did not have correct "
|
||||
"Authenticator - dropped\n");
|
||||
return RADIUS_RX_INVALID_AUTHENTICATOR;
|
||||
@ -395,7 +411,7 @@ static void accounting_report_state(struct hostapd_data *hapd, int on)
|
||||
{
|
||||
struct radius_msg *msg;
|
||||
|
||||
if (!hapd->conf->acct_server || hapd->radius == NULL)
|
||||
if (!hapd->conf->radius->acct_server || hapd->radius == NULL)
|
||||
return;
|
||||
|
||||
/* Inform RADIUS server that accounting will start/stop so that the
|
||||
|
@ -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 */
|
||||
|
@ -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 { \
|
||||
|
@ -28,18 +28,20 @@
|
||||
#include "driver.h"
|
||||
#include "sha1.h"
|
||||
#include "eap.h"
|
||||
#include "radius_client.h"
|
||||
|
||||
|
||||
static struct hostapd_config *hostapd_config_defaults(void)
|
||||
{
|
||||
struct hostapd_config *conf;
|
||||
|
||||
conf = malloc(sizeof(*conf));
|
||||
conf = malloc(sizeof(*conf) + sizeof(struct hostapd_radius_servers));
|
||||
if (conf == NULL) {
|
||||
printf("Failed to allocate memory for configuration data.\n");
|
||||
return NULL;
|
||||
}
|
||||
memset(conf, 0, sizeof(*conf));
|
||||
memset(conf, 0, sizeof(*conf) + sizeof(struct hostapd_radius_servers));
|
||||
conf->radius = (struct hostapd_radius_servers *) (conf + 1);
|
||||
|
||||
/* set default driver based on configuration */
|
||||
conf->driver = driver_lookup("default");
|
||||
@ -71,6 +73,24 @@ static struct hostapd_config *hostapd_config_defaults(void)
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_parse_ip_addr(const char *txt, struct hostapd_ip_addr *addr)
|
||||
{
|
||||
if (inet_aton(txt, &addr->u.v4)) {
|
||||
addr->af = AF_INET;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IPV6
|
||||
if (inet_pton(AF_INET6, txt, &addr->u.v6) > 0) {
|
||||
addr->af = AF_INET6;
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_IPV6 */
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int mac_comp(const void *a, const void *b)
|
||||
{
|
||||
return memcmp(a, b, sizeof(macaddr));
|
||||
@ -269,12 +289,12 @@ int hostapd_setup_wpa_psk(struct hostapd_config *conf)
|
||||
}
|
||||
|
||||
|
||||
#ifdef EAP_AUTHENTICATOR
|
||||
#ifdef EAP_SERVER
|
||||
static int hostapd_config_read_eap_user(const char *fname,
|
||||
struct hostapd_config *conf)
|
||||
{
|
||||
FILE *f;
|
||||
char buf[512], *pos, *start;
|
||||
char buf[512], *pos, *start, *pos2;
|
||||
int line = 0, ret = 0, num_methods;
|
||||
struct hostapd_eap_user *user, *tail = NULL;
|
||||
|
||||
@ -410,30 +430,53 @@ static int hostapd_config_read_eap_user(const char *fname,
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (*pos != '"') {
|
||||
printf("Invalid EAP password (no \" in start) on "
|
||||
"line %d in '%s'\n", line, fname);
|
||||
goto failed;
|
||||
}
|
||||
pos++;
|
||||
start = pos;
|
||||
while (*pos != '"' && *pos != '\0')
|
||||
if (*pos == '"') {
|
||||
pos++;
|
||||
if (*pos == '\0') {
|
||||
printf("Invalid EAP password (no \" in end) on "
|
||||
"line %d in '%s'\n", line, fname);
|
||||
goto failed;
|
||||
start = pos;
|
||||
while (*pos != '"' && *pos != '\0')
|
||||
pos++;
|
||||
if (*pos == '\0') {
|
||||
printf("Invalid EAP password (no \" in end) "
|
||||
"on line %d in '%s'\n", line, fname);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
user->password = malloc(pos - start);
|
||||
if (user->password == NULL) {
|
||||
printf("Failed to allocate memory for EAP "
|
||||
"password\n");
|
||||
goto failed;
|
||||
}
|
||||
memcpy(user->password, start, pos - start);
|
||||
user->password_len = pos - start;
|
||||
|
||||
pos++;
|
||||
} else {
|
||||
pos2 = pos;
|
||||
while (*pos2 != '\0' && *pos2 != ' ' &&
|
||||
*pos2 != '\t' && *pos2 != '#')
|
||||
pos2++;
|
||||
if ((pos2 - pos) & 1) {
|
||||
printf("Invalid hex password on line %d in "
|
||||
"'%s'\n", line, fname);
|
||||
goto failed;
|
||||
}
|
||||
user->password = malloc((pos2 - pos) / 2);
|
||||
if (user->password == NULL) {
|
||||
printf("Failed to allocate memory for EAP "
|
||||
"password\n");
|
||||
goto failed;
|
||||
}
|
||||
if (hexstr2bin(pos, user->password,
|
||||
(pos2 - pos) / 2) < 0) {
|
||||
printf("Invalid hex password on line %d in "
|
||||
"'%s'\n", line, fname);
|
||||
goto failed;
|
||||
}
|
||||
user->password_len = (pos2 - pos) / 2;
|
||||
pos = pos2;
|
||||
}
|
||||
|
||||
user->password = malloc(pos - start);
|
||||
if (user->password == NULL) {
|
||||
printf("Failed to allocate memory for EAP password\n");
|
||||
goto failed;
|
||||
}
|
||||
memcpy(user->password, start, pos - start);
|
||||
user->password_len = pos - start;
|
||||
|
||||
pos++;
|
||||
while (*pos == ' ' || *pos == '\t')
|
||||
pos++;
|
||||
if (strncmp(pos, "[2]", 3) == 0) {
|
||||
@ -462,7 +505,7 @@ static int hostapd_config_read_eap_user(const char *fname,
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* EAP_AUTHENTICATOR */
|
||||
#endif /* EAP_SERVER */
|
||||
|
||||
|
||||
static int
|
||||
@ -485,7 +528,7 @@ hostapd_config_read_radius_addr(struct hostapd_radius_server **server,
|
||||
|
||||
memset(nserv, 0, sizeof(*nserv));
|
||||
nserv->port = def_port;
|
||||
ret = !inet_aton(val, &nserv->addr);
|
||||
ret = hostapd_parse_ip_addr(val, &nserv->addr);
|
||||
nserv->index = server_index++;
|
||||
|
||||
return ret;
|
||||
@ -589,8 +632,8 @@ static int hostapd_config_parse_cipher(int line, const char *value)
|
||||
|
||||
static int hostapd_config_check(struct hostapd_config *conf)
|
||||
{
|
||||
if (conf->ieee802_1x && !conf->eap_authenticator &&
|
||||
!conf->auth_servers) {
|
||||
if (conf->ieee802_1x && !conf->eap_server &&
|
||||
!conf->radius->auth_servers) {
|
||||
printf("Invalid IEEE 802.1X configuration (no EAP "
|
||||
"authenticator configured).\n");
|
||||
return -1;
|
||||
@ -616,9 +659,9 @@ struct hostapd_config * hostapd_config_read(const char *fname)
|
||||
int line = 0;
|
||||
int errors = 0;
|
||||
char *accept_mac_file = NULL, *deny_mac_file = NULL;
|
||||
#ifdef EAP_AUTHENTICATOR
|
||||
#ifdef EAP_SERVER
|
||||
char *eap_user_file = NULL;
|
||||
#endif /* EAP_AUTHENTICATOR */
|
||||
#endif /* EAP_SERVER */
|
||||
|
||||
f = fopen(fname, "r");
|
||||
if (f == NULL) {
|
||||
@ -722,9 +765,13 @@ struct hostapd_config * hostapd_config_read(const char *fname)
|
||||
conf->assoc_ap = 1;
|
||||
} else if (strcmp(buf, "ieee8021x") == 0) {
|
||||
conf->ieee802_1x = atoi(pos);
|
||||
#ifdef EAP_AUTHENTICATOR
|
||||
#ifdef EAP_SERVER
|
||||
} else if (strcmp(buf, "eap_authenticator") == 0) {
|
||||
conf->eap_authenticator = atoi(pos);
|
||||
conf->eap_server = atoi(pos);
|
||||
printf("Line %d: obsolete eap_authenticator used; "
|
||||
"this has been renamed to eap_server\n", line);
|
||||
} else if (strcmp(buf, "eap_server") == 0) {
|
||||
conf->eap_server = atoi(pos);
|
||||
} else if (strcmp(buf, "eap_user_file") == 0) {
|
||||
free(eap_user_file);
|
||||
eap_user_file = strdup(pos);
|
||||
@ -744,14 +791,33 @@ struct hostapd_config * hostapd_config_read(const char *fname)
|
||||
} else if (strcmp(buf, "private_key_passwd") == 0) {
|
||||
free(conf->private_key_passwd);
|
||||
conf->private_key_passwd = strdup(pos);
|
||||
} else if (strcmp(buf, "check_crl") == 0) {
|
||||
conf->check_crl = atoi(pos);
|
||||
#ifdef EAP_SIM
|
||||
} else if (strcmp(buf, "eap_sim_db") == 0) {
|
||||
free(conf->eap_sim_db);
|
||||
conf->eap_sim_db = strdup(pos);
|
||||
#endif /* EAP_SIM */
|
||||
#endif /* EAP_AUTHENTICATOR */
|
||||
#endif /* EAP_SERVER */
|
||||
} else if (strcmp(buf, "eap_message") == 0) {
|
||||
char *term;
|
||||
conf->eap_req_id_text = strdup(pos);
|
||||
if (conf->eap_req_id_text == NULL) {
|
||||
printf("Line %d: Failed to allocate memory "
|
||||
"for eap_req_id_text\n", line);
|
||||
errors++;
|
||||
continue;
|
||||
}
|
||||
conf->eap_req_id_text_len =
|
||||
strlen(conf->eap_req_id_text);
|
||||
term = strstr(conf->eap_req_id_text, "\\0");
|
||||
if (term) {
|
||||
*term++ = '\0';
|
||||
memmove(term, term + 1,
|
||||
conf->eap_req_id_text_len -
|
||||
(term - conf->eap_req_id_text) - 1);
|
||||
conf->eap_req_id_text_len--;
|
||||
}
|
||||
} else if (strcmp(buf, "wep_key_len_broadcast") == 0) {
|
||||
conf->default_wep_key_len = atoi(pos);
|
||||
if (conf->default_wep_key_len > 13) {
|
||||
@ -796,7 +862,7 @@ struct hostapd_config * hostapd_config_read(const char *fname)
|
||||
"%s", pos);
|
||||
#endif /* CONFIG_IAPP */
|
||||
} else if (strcmp(buf, "own_ip_addr") == 0) {
|
||||
if (!inet_aton(pos, &conf->own_ip_addr)) {
|
||||
if (hostapd_parse_ip_addr(pos, &conf->own_ip_addr)) {
|
||||
printf("Line %d: invalid IP address '%s'\n",
|
||||
line, pos);
|
||||
errors++;
|
||||
@ -805,17 +871,17 @@ struct hostapd_config * hostapd_config_read(const char *fname)
|
||||
conf->nas_identifier = strdup(pos);
|
||||
} else if (strcmp(buf, "auth_server_addr") == 0) {
|
||||
if (hostapd_config_read_radius_addr(
|
||||
&conf->auth_servers,
|
||||
&conf->num_auth_servers, pos, 1812,
|
||||
&conf->auth_server)) {
|
||||
&conf->radius->auth_servers,
|
||||
&conf->radius->num_auth_servers, pos, 1812,
|
||||
&conf->radius->auth_server)) {
|
||||
printf("Line %d: invalid IP address '%s'\n",
|
||||
line, pos);
|
||||
errors++;
|
||||
}
|
||||
} else if (conf->auth_server &&
|
||||
} else if (conf->radius->auth_server &&
|
||||
strcmp(buf, "auth_server_port") == 0) {
|
||||
conf->auth_server->port = atoi(pos);
|
||||
} else if (conf->auth_server &&
|
||||
conf->radius->auth_server->port = atoi(pos);
|
||||
} else if (conf->radius->auth_server &&
|
||||
strcmp(buf, "auth_server_shared_secret") == 0) {
|
||||
int len = strlen(pos);
|
||||
if (len == 0) {
|
||||
@ -824,21 +890,22 @@ struct hostapd_config * hostapd_config_read(const char *fname)
|
||||
"allowed.\n", line);
|
||||
errors++;
|
||||
}
|
||||
conf->auth_server->shared_secret = (u8 *) strdup(pos);
|
||||
conf->auth_server->shared_secret_len = len;
|
||||
conf->radius->auth_server->shared_secret =
|
||||
(u8 *) strdup(pos);
|
||||
conf->radius->auth_server->shared_secret_len = len;
|
||||
} else if (strcmp(buf, "acct_server_addr") == 0) {
|
||||
if (hostapd_config_read_radius_addr(
|
||||
&conf->acct_servers,
|
||||
&conf->num_acct_servers, pos, 1813,
|
||||
&conf->acct_server)) {
|
||||
&conf->radius->acct_servers,
|
||||
&conf->radius->num_acct_servers, pos, 1813,
|
||||
&conf->radius->acct_server)) {
|
||||
printf("Line %d: invalid IP address '%s'\n",
|
||||
line, pos);
|
||||
errors++;
|
||||
}
|
||||
} else if (conf->acct_server &&
|
||||
} else if (conf->radius->acct_server &&
|
||||
strcmp(buf, "acct_server_port") == 0) {
|
||||
conf->acct_server->port = atoi(pos);
|
||||
} else if (conf->acct_server &&
|
||||
conf->radius->acct_server->port = atoi(pos);
|
||||
} else if (conf->radius->acct_server &&
|
||||
strcmp(buf, "acct_server_shared_secret") == 0) {
|
||||
int len = strlen(pos);
|
||||
if (len == 0) {
|
||||
@ -847,12 +914,13 @@ struct hostapd_config * hostapd_config_read(const char *fname)
|
||||
"allowed.\n", line);
|
||||
errors++;
|
||||
}
|
||||
conf->acct_server->shared_secret = (u8 *) strdup(pos);
|
||||
conf->acct_server->shared_secret_len = len;
|
||||
conf->radius->acct_server->shared_secret =
|
||||
(u8 *) strdup(pos);
|
||||
conf->radius->acct_server->shared_secret_len = len;
|
||||
} else if (strcmp(buf, "radius_retry_primary_interval") == 0) {
|
||||
conf->radius_retry_primary_interval = atoi(pos);
|
||||
conf->radius->retry_primary_interval = atoi(pos);
|
||||
} else if (strcmp(buf, "radius_acct_interim_interval") == 0) {
|
||||
conf->radius_acct_interim_interval = atoi(pos);
|
||||
conf->radius->acct_interim_interval = atoi(pos);
|
||||
} else if (strcmp(buf, "auth_algs") == 0) {
|
||||
conf->auth_algs = atoi(pos);
|
||||
if (conf->auth_algs == 0) {
|
||||
@ -944,6 +1012,7 @@ struct hostapd_config * hostapd_config_read(const char *fname)
|
||||
grp = getgrnam(group);
|
||||
if (grp) {
|
||||
conf->ctrl_interface_gid = grp->gr_gid;
|
||||
conf->ctrl_interface_gid_set = 1;
|
||||
wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
|
||||
" (from group name '%s')",
|
||||
conf->ctrl_interface_gid, group);
|
||||
@ -958,6 +1027,7 @@ struct hostapd_config * hostapd_config_read(const char *fname)
|
||||
errors++;
|
||||
continue;
|
||||
}
|
||||
conf->ctrl_interface_gid_set = 1;
|
||||
wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
|
||||
conf->ctrl_interface_gid);
|
||||
#ifdef RADIUS_SERVER
|
||||
@ -966,7 +1036,14 @@ struct hostapd_config * hostapd_config_read(const char *fname)
|
||||
conf->radius_server_clients = strdup(pos);
|
||||
} else if (strcmp(buf, "radius_server_auth_port") == 0) {
|
||||
conf->radius_server_auth_port = atoi(pos);
|
||||
} else if (strcmp(buf, "radius_server_ipv6") == 0) {
|
||||
conf->radius_server_ipv6 = atoi(pos);
|
||||
#endif /* RADIUS_SERVER */
|
||||
} else if (strcmp(buf, "test_socket") == 0) {
|
||||
free(conf->test_socket);
|
||||
conf->test_socket = strdup(pos);
|
||||
} else if (strcmp(buf, "use_pae_group_addr") == 0) {
|
||||
conf->use_pae_group_addr = atoi(pos);
|
||||
} else {
|
||||
printf("Line %d: unknown configuration item '%s'\n",
|
||||
line, buf);
|
||||
@ -985,14 +1062,14 @@ struct hostapd_config * hostapd_config_read(const char *fname)
|
||||
errors++;
|
||||
free(deny_mac_file);
|
||||
|
||||
#ifdef EAP_AUTHENTICATOR
|
||||
#ifdef EAP_SERVER
|
||||
if (hostapd_config_read_eap_user(eap_user_file, conf))
|
||||
errors++;
|
||||
free(eap_user_file);
|
||||
#endif /* EAP_AUTHENTICATOR */
|
||||
#endif /* EAP_SERVER */
|
||||
|
||||
conf->auth_server = conf->auth_servers;
|
||||
conf->acct_server = conf->acct_servers;
|
||||
conf->radius->auth_server = conf->radius->auth_servers;
|
||||
conf->radius->acct_server = conf->radius->acct_servers;
|
||||
|
||||
if (hostapd_config_check(conf))
|
||||
errors++;
|
||||
@ -1058,8 +1135,10 @@ void hostapd_config_free(struct hostapd_config *conf)
|
||||
free(conf->accept_mac);
|
||||
free(conf->deny_mac);
|
||||
free(conf->nas_identifier);
|
||||
hostapd_config_free_radius(conf->auth_servers, conf->num_auth_servers);
|
||||
hostapd_config_free_radius(conf->acct_servers, conf->num_acct_servers);
|
||||
hostapd_config_free_radius(conf->radius->auth_servers,
|
||||
conf->radius->num_auth_servers);
|
||||
hostapd_config_free_radius(conf->radius->acct_servers,
|
||||
conf->radius->num_acct_servers);
|
||||
free(conf->rsn_preauth_interfaces);
|
||||
free(conf->ctrl_interface);
|
||||
free(conf->ca_cert);
|
||||
@ -1068,6 +1147,7 @@ void hostapd_config_free(struct hostapd_config *conf)
|
||||
free(conf->private_key_passwd);
|
||||
free(conf->eap_sim_db);
|
||||
free(conf->radius_server_clients);
|
||||
free(conf->test_socket);
|
||||
free(conf);
|
||||
}
|
||||
|
||||
|
@ -1,34 +1,11 @@
|
||||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
#include "config_types.h"
|
||||
|
||||
typedef u8 macaddr[ETH_ALEN];
|
||||
|
||||
struct hostapd_radius_server {
|
||||
/* MIB prefix for shared variables:
|
||||
* @ = radiusAuth or radiusAcc depending on the type of the server */
|
||||
struct in_addr addr; /* @ServerAddress */
|
||||
int port; /* @ClientServerPortNumber */
|
||||
u8 *shared_secret;
|
||||
size_t shared_secret_len;
|
||||
|
||||
/* Dynamic (not from configuration file) MIB data */
|
||||
int index; /* @ServerIndex */
|
||||
int round_trip_time; /* @ClientRoundTripTime; in hundredths of a
|
||||
* second */
|
||||
u32 requests; /* @Client{Access,}Requests */
|
||||
u32 retransmissions; /* @Client{Access,}Retransmissions */
|
||||
u32 access_accepts; /* radiusAuthClientAccessAccepts */
|
||||
u32 access_rejects; /* radiusAuthClientAccessRejects */
|
||||
u32 access_challenges; /* radiusAuthClientAccessChallenges */
|
||||
u32 responses; /* radiusAccClientResponses */
|
||||
u32 malformed_responses; /* @ClientMalformed{Access,}Responses */
|
||||
u32 bad_authenticators; /* @ClientBadAuthenticators */
|
||||
u32 timeouts; /* @ClientTimeouts */
|
||||
u32 unknown_types; /* @ClientUnknownTypes */
|
||||
u32 packets_dropped; /* @ClientPacketsDropped */
|
||||
/* @ClientPendingRequests: length of hapd->radius->msgs for matching
|
||||
* msg_type */
|
||||
};
|
||||
struct hostapd_radius_servers;
|
||||
|
||||
#define PMK_LEN 32
|
||||
struct hostapd_wpa_psk {
|
||||
@ -80,26 +57,21 @@ struct hostapd_config {
|
||||
char *dump_log_name; /* file name for state dump (SIGUSR1) */
|
||||
|
||||
int ieee802_1x; /* use IEEE 802.1X */
|
||||
int eap_authenticator; /* Use internal EAP authenticator instead of
|
||||
* external RADIUS server */
|
||||
int eap_server; /* Use internal EAP server instead of external
|
||||
* RADIUS server */
|
||||
struct hostapd_eap_user *eap_user;
|
||||
char *eap_sim_db;
|
||||
struct in_addr own_ip_addr;
|
||||
struct hostapd_ip_addr own_ip_addr;
|
||||
char *nas_identifier;
|
||||
/* RADIUS Authentication and Accounting servers in priority order */
|
||||
struct hostapd_radius_server *auth_servers, *auth_server;
|
||||
int num_auth_servers;
|
||||
struct hostapd_radius_server *acct_servers, *acct_server;
|
||||
int num_acct_servers;
|
||||
struct hostapd_radius_servers *radius;
|
||||
|
||||
int radius_retry_primary_interval;
|
||||
int radius_acct_interim_interval;
|
||||
#define HOSTAPD_SSID_LEN 32
|
||||
char ssid[HOSTAPD_SSID_LEN + 1];
|
||||
size_t ssid_len;
|
||||
int ssid_set;
|
||||
char *eap_req_id_text; /* optional displayable message sent with
|
||||
* EAP Request-Identity */
|
||||
size_t eap_req_id_text_len;
|
||||
int eapol_key_index_workaround;
|
||||
|
||||
size_t default_wep_key_len;
|
||||
@ -153,14 +125,24 @@ struct hostapd_config {
|
||||
|
||||
char *ctrl_interface; /* directory for UNIX domain sockets */
|
||||
gid_t ctrl_interface_gid;
|
||||
int ctrl_interface_gid_set;
|
||||
|
||||
char *ca_cert;
|
||||
char *server_cert;
|
||||
char *private_key;
|
||||
char *private_key_passwd;
|
||||
int check_crl;
|
||||
|
||||
char *radius_server_clients;
|
||||
int radius_server_auth_port;
|
||||
int radius_server_ipv6;
|
||||
|
||||
char *test_socket; /* UNIX domain socket path for driver_test */
|
||||
|
||||
int use_pae_group_addr; /* Whether to send EAPOL frames to PAE group
|
||||
* address instead of individual address
|
||||
* (for driver_wired.c).
|
||||
*/
|
||||
};
|
||||
|
||||
|
||||
|
14
contrib/hostapd/config_types.h
Normal file
14
contrib/hostapd/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 */
|
||||
|
@ -315,7 +315,8 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
|
||||
}
|
||||
}
|
||||
|
||||
if (chown(hapd->conf->ctrl_interface, 0,
|
||||
if (hapd->conf->ctrl_interface_gid_set &&
|
||||
chown(hapd->conf->ctrl_interface, 0,
|
||||
hapd->conf->ctrl_interface_gid) < 0) {
|
||||
perror("chown[ctrl_interface]");
|
||||
return -1;
|
||||
@ -342,7 +343,8 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (chown(fname, 0, hapd->conf->ctrl_interface_gid) < 0) {
|
||||
if (hapd->conf->ctrl_interface_gid_set &&
|
||||
chown(fname, 0, hapd->conf->ctrl_interface_gid) < 0) {
|
||||
perror("chown[ctrl_interface/ifname]");
|
||||
goto fail;
|
||||
}
|
||||
|
@ -33,34 +33,43 @@ CONFIG_IAPP=y
|
||||
# WPA2/IEEE 802.11i RSN pre-authentication
|
||||
CONFIG_RSN_PREAUTH=y
|
||||
|
||||
# Integrated EAP authenticator
|
||||
# Integrated EAP server
|
||||
CONFIG_EAP=y
|
||||
|
||||
# EAP-MD5 for the integrated EAP authenticator
|
||||
# EAP-MD5 for the integrated EAP server
|
||||
CONFIG_EAP_MD5=y
|
||||
|
||||
# EAP-TLS for the integrated EAP authenticator
|
||||
# EAP-TLS for the integrated EAP server
|
||||
CONFIG_EAP_TLS=y
|
||||
|
||||
# EAP-MSCHAPv2 for the integrated EAP authenticator
|
||||
# EAP-MSCHAPv2 for the integrated EAP server
|
||||
CONFIG_EAP_MSCHAPV2=y
|
||||
|
||||
# EAP-PEAP for the integrated EAP authenticator
|
||||
# EAP-PEAP for the integrated EAP server
|
||||
CONFIG_EAP_PEAP=y
|
||||
|
||||
# EAP-GTC for the integrated EAP authenticator
|
||||
# EAP-GTC for the integrated EAP server
|
||||
CONFIG_EAP_GTC=y
|
||||
|
||||
# EAP-TTLS for the integrated EAP authenticator
|
||||
# EAP-TTLS for the integrated EAP server
|
||||
CONFIG_EAP_TTLS=y
|
||||
|
||||
# EAP-SIM for the integrated EAP authenticator
|
||||
# EAP-SIM for the integrated EAP server
|
||||
#CONFIG_EAP_SIM=y
|
||||
|
||||
# EAP-PAX for the integrated EAP server
|
||||
#CONFIG_EAP_PAX=y
|
||||
|
||||
# EAP-PSK for the integrated EAP server (this is _not_ needed for WPA-PSK)
|
||||
#CONFIG_EAP_PSK=y
|
||||
|
||||
# PKCS#12 (PFX) support (used to read private key and certificate file from
|
||||
# a file that usually has extension .p12 or .pfx)
|
||||
CONFIG_PKCS12=y
|
||||
|
||||
# RADIUS authentication server. This provides access to the integrated EAP
|
||||
# authenticator from external hosts using RADIUS.
|
||||
# server from external hosts using RADIUS.
|
||||
#CONFIG_RADIUS_SERVER=y
|
||||
|
||||
# Build IPv6 support for RADIUS operations
|
||||
CONFIG_IPV6=y
|
||||
|
@ -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 */
|
||||
|
@ -11,14 +11,14 @@ struct driver_ops {
|
||||
void (*wireless_event_deinit)(void *priv);
|
||||
|
||||
/**
|
||||
* set_8021x - enable/disable 802.1x support
|
||||
* set_8021x - enable/disable IEEE 802.1X support
|
||||
* @priv: driver private data
|
||||
* @enabled: 1 = enable, 0 = disable
|
||||
*
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*
|
||||
* Configure the kernel driver to enable/disable 802.1x support.
|
||||
* This may be an empty function if 802.1x support is always enabled.
|
||||
* Configure the kernel driver to enable/disable 802.1X support.
|
||||
* This may be an empty function if 802.1X support is always enabled.
|
||||
*/
|
||||
int (*set_ieee8021x)(void *priv, int enabled);
|
||||
|
||||
@ -49,6 +49,7 @@ struct driver_ops {
|
||||
int (*sta_remove)(void *priv, u8 *addr);
|
||||
int (*get_ssid)(void *priv, u8 *buf, int len);
|
||||
int (*set_ssid)(void *priv, u8 *buf, int len);
|
||||
int (*set_countermeasures)(void *priv, int enabled);
|
||||
int (*send_mgmt_frame)(void *priv, const void *msg, size_t len,
|
||||
int flags);
|
||||
int (*set_assoc_ap)(void *priv, u8 *addr);
|
||||
@ -228,6 +229,14 @@ hostapd_set_assoc_ap(struct hostapd_data *hapd, u8 *addr)
|
||||
return hapd->driver->set_assoc_ap(hapd->driver, addr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_set_countermeasures(struct hostapd_data *hapd, int enabled)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->set_countermeasures == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_countermeasures(hapd->driver, enabled);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_sta_add(struct hostapd_data *hapd, u8 *addr, u16 aid, u16 capability,
|
||||
u8 tx_supp_rates)
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Host AP (software wireless LAN access point) user space daemon for
|
||||
* Host AP kernel driver / Driver interface for development testing
|
||||
* 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
|
||||
@ -23,22 +23,390 @@
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include "hostapd.h"
|
||||
#include "driver.h"
|
||||
#include "sha1.h"
|
||||
#include "eloop.h"
|
||||
#include "ieee802_1x.h"
|
||||
#include "sta_info.h"
|
||||
#include "eapol_sm.h"
|
||||
#include "wpa.h"
|
||||
#include "accounting.h"
|
||||
#include "radius.h"
|
||||
#include "l2_packet.h"
|
||||
#include "hostap_common.h"
|
||||
|
||||
|
||||
struct test_client_socket {
|
||||
struct test_client_socket *next;
|
||||
u8 addr[ETH_ALEN];
|
||||
struct sockaddr_un un;
|
||||
socklen_t unlen;
|
||||
};
|
||||
|
||||
struct test_driver_data {
|
||||
struct driver_ops ops;
|
||||
struct hostapd_data *hapd;
|
||||
struct test_client_socket *cli;
|
||||
int test_socket;
|
||||
u8 *ie;
|
||||
size_t ielen;
|
||||
};
|
||||
|
||||
static const struct driver_ops test_driver_ops;
|
||||
|
||||
|
||||
static struct test_client_socket *
|
||||
test_driver_get_cli(struct test_driver_data *drv, struct sockaddr_un *from,
|
||||
socklen_t fromlen)
|
||||
{
|
||||
struct test_client_socket *cli = drv->cli;
|
||||
|
||||
while (cli) {
|
||||
if (cli->unlen == fromlen &&
|
||||
strncmp(cli->un.sun_path, from->sun_path, fromlen) == 0)
|
||||
return cli;
|
||||
cli = cli->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int test_driver_send_eapol(void *priv, u8 *addr, u8 *data,
|
||||
size_t data_len, int encrypt)
|
||||
{
|
||||
struct test_driver_data *drv = priv;
|
||||
struct test_client_socket *cli;
|
||||
struct msghdr msg;
|
||||
struct iovec io[3];
|
||||
struct l2_ethhdr eth;
|
||||
|
||||
if (drv->test_socket < 0)
|
||||
return -1;
|
||||
|
||||
cli = drv->cli;
|
||||
while (cli) {
|
||||
if (memcmp(cli->addr, addr, ETH_ALEN) == 0)
|
||||
break;
|
||||
cli = cli->next;
|
||||
}
|
||||
|
||||
if (!cli)
|
||||
return -1;
|
||||
|
||||
memcpy(eth.h_dest, addr, ETH_ALEN);
|
||||
memcpy(eth.h_source, drv->hapd->own_addr, ETH_ALEN);
|
||||
eth.h_proto = htons(ETH_P_EAPOL);
|
||||
|
||||
io[0].iov_base = "EAPOL ";
|
||||
io[0].iov_len = 6;
|
||||
io[1].iov_base = ð
|
||||
io[1].iov_len = sizeof(eth);
|
||||
io[2].iov_base = data;
|
||||
io[2].iov_len = data_len;
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.msg_iov = io;
|
||||
msg.msg_iovlen = 3;
|
||||
msg.msg_name = &cli->un;
|
||||
msg.msg_namelen = cli->unlen;
|
||||
return sendmsg(drv->test_socket, &msg, 0);
|
||||
}
|
||||
|
||||
|
||||
static void test_driver_scan(struct test_driver_data *drv,
|
||||
struct sockaddr_un *from, socklen_t fromlen)
|
||||
{
|
||||
char buf[512], *pos, *end;
|
||||
int i;
|
||||
|
||||
pos = buf;
|
||||
end = buf + sizeof(buf);
|
||||
|
||||
wpa_printf(MSG_DEBUG, "test_driver: SCAN");
|
||||
|
||||
/* reply: SCANRESP BSSID SSID IEs */
|
||||
pos += snprintf(pos, end - pos, "SCANRESP " MACSTR " ",
|
||||
MAC2STR(drv->hapd->own_addr));
|
||||
for (i = 0; i < drv->hapd->conf->ssid_len; i++) {
|
||||
pos += snprintf(pos, end - pos, "%02x",
|
||||
drv->hapd->conf->ssid[i]);
|
||||
}
|
||||
pos += snprintf(pos, end - pos, " ");
|
||||
for (i = 0; i < drv->ielen; i++) {
|
||||
pos += snprintf(pos, end - pos, "%02x",
|
||||
drv->ie[i]);
|
||||
}
|
||||
|
||||
sendto(drv->test_socket, buf, pos - buf, 0,
|
||||
(struct sockaddr *) from, fromlen);
|
||||
}
|
||||
|
||||
|
||||
static int test_driver_new_sta(struct test_driver_data *drv, const u8 *addr,
|
||||
const u8 *ie, size_t ielen)
|
||||
{
|
||||
struct hostapd_data *hapd = drv->hapd;
|
||||
struct sta_info *sta;
|
||||
int new_assoc, res;
|
||||
|
||||
hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_INFO, "associated");
|
||||
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (sta) {
|
||||
accounting_sta_stop(hapd, sta);
|
||||
} else {
|
||||
sta = ap_sta_add(hapd, addr);
|
||||
if (sta == NULL)
|
||||
return -1;
|
||||
}
|
||||
accounting_sta_get_id(hapd, sta);
|
||||
|
||||
if (hapd->conf->wpa) {
|
||||
if (ie == NULL || ielen == 0) {
|
||||
printf("test_driver: no IE from STA\n");
|
||||
return -1;
|
||||
}
|
||||
res = wpa_validate_wpa_ie(hapd, sta, ie, ielen,
|
||||
ie[0] == WLAN_EID_RSN ?
|
||||
HOSTAPD_WPA_VERSION_WPA2 :
|
||||
HOSTAPD_WPA_VERSION_WPA);
|
||||
if (res != WPA_IE_OK) {
|
||||
printf("WPA/RSN information element rejected? "
|
||||
"(res %u)\n", res);
|
||||
return -1;
|
||||
}
|
||||
free(sta->wpa_ie);
|
||||
sta->wpa_ie = malloc(ielen);
|
||||
if (sta->wpa_ie == NULL)
|
||||
return -1;
|
||||
memcpy(sta->wpa_ie, ie, ielen);
|
||||
sta->wpa_ie_len = ielen;
|
||||
} else {
|
||||
free(sta->wpa_ie);
|
||||
sta->wpa_ie = NULL;
|
||||
sta->wpa_ie_len = 0;
|
||||
}
|
||||
|
||||
new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
|
||||
sta->flags |= WLAN_STA_ASSOC;
|
||||
wpa_sm_event(hapd, sta, WPA_ASSOC);
|
||||
|
||||
hostapd_new_assoc_sta(hapd, sta, !new_assoc);
|
||||
|
||||
ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void test_driver_assoc(struct test_driver_data *drv,
|
||||
struct sockaddr_un *from, socklen_t fromlen,
|
||||
char *data)
|
||||
{
|
||||
struct test_client_socket *cli;
|
||||
u8 ie[256];
|
||||
size_t ielen;
|
||||
char *pos, *pos2, cmd[50];
|
||||
|
||||
/* data: STA-addr SSID(hex) IEs(hex) */
|
||||
|
||||
cli = malloc(sizeof(*cli));
|
||||
if (cli == NULL)
|
||||
return;
|
||||
|
||||
memset(cli, 0, sizeof(*cli));
|
||||
if (hwaddr_aton(data, cli->addr)) {
|
||||
printf("test_socket: Invalid MAC address '%s' in ASSOC\n",
|
||||
data);
|
||||
free(cli);
|
||||
return;
|
||||
}
|
||||
pos = data + 17;
|
||||
while (*pos == ' ')
|
||||
pos++;
|
||||
pos2 = strchr(pos, ' ');
|
||||
ielen = 0;
|
||||
if (pos2) {
|
||||
/* TODO: verify SSID */
|
||||
|
||||
pos = pos2 + 1;
|
||||
ielen = strlen(pos) / 2;
|
||||
if (ielen > sizeof(ie))
|
||||
ielen = sizeof(ie);
|
||||
if (hexstr2bin(pos, ie, ielen) < 0)
|
||||
ielen = 0;
|
||||
}
|
||||
|
||||
memcpy(&cli->un, from, sizeof(cli->un));
|
||||
cli->unlen = fromlen;
|
||||
cli->next = drv->cli;
|
||||
drv->cli = cli;
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "test_socket: ASSOC sun_path",
|
||||
cli->un.sun_path, cli->unlen);
|
||||
|
||||
snprintf(cmd, sizeof(cmd), "ASSOCRESP " MACSTR " 0",
|
||||
MAC2STR(drv->hapd->own_addr));
|
||||
sendto(drv->test_socket, cmd, strlen(cmd), 0,
|
||||
(struct sockaddr *) from, fromlen);
|
||||
|
||||
if (test_driver_new_sta(drv, cli->addr, ie, ielen) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "test_driver: failed to add new STA");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_driver_disassoc(struct test_driver_data *drv,
|
||||
struct sockaddr_un *from, socklen_t fromlen)
|
||||
{
|
||||
struct test_client_socket *cli;
|
||||
struct sta_info *sta;
|
||||
|
||||
cli = test_driver_get_cli(drv, from, fromlen);
|
||||
if (!cli)
|
||||
return;
|
||||
|
||||
hostapd_logger(drv->hapd, cli->addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_INFO, "disassociated");
|
||||
|
||||
sta = ap_get_sta(drv->hapd, cli->addr);
|
||||
if (sta != NULL) {
|
||||
sta->flags &= ~WLAN_STA_ASSOC;
|
||||
wpa_sm_event(drv->hapd, sta, WPA_DISASSOC);
|
||||
sta->acct_terminate_cause =
|
||||
RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
|
||||
ieee802_1x_set_port_enabled(drv->hapd, sta, 0);
|
||||
ap_free_sta(drv->hapd, sta);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_driver_eapol(struct test_driver_data *drv,
|
||||
struct sockaddr_un *from, socklen_t fromlen,
|
||||
u8 *data, size_t datalen)
|
||||
{
|
||||
struct test_client_socket *cli;
|
||||
if (datalen > 14) {
|
||||
/* Skip Ethernet header */
|
||||
data += 14;
|
||||
datalen -= 14;
|
||||
}
|
||||
cli = test_driver_get_cli(drv, from, fromlen);
|
||||
if (cli)
|
||||
ieee802_1x_receive(drv->hapd, cli->addr, data, datalen);
|
||||
else {
|
||||
wpa_printf(MSG_DEBUG, "test_socket: EAPOL from unknown "
|
||||
"client");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_driver_receive_unix(int sock, void *eloop_ctx, void *sock_ctx)
|
||||
{
|
||||
struct test_driver_data *drv = eloop_ctx;
|
||||
char buf[2000];
|
||||
int res;
|
||||
struct sockaddr_un from;
|
||||
socklen_t fromlen = sizeof(from);
|
||||
|
||||
res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
|
||||
(struct sockaddr *) &from, &fromlen);
|
||||
if (res < 0) {
|
||||
perror("recvfrom(test_socket)");
|
||||
return;
|
||||
}
|
||||
buf[res] = '\0';
|
||||
|
||||
wpa_printf(MSG_DEBUG, "test_driver: received %u bytes", res);
|
||||
|
||||
if (strcmp(buf, "SCAN") == 0) {
|
||||
test_driver_scan(drv, &from, fromlen);
|
||||
} else if (strncmp(buf, "ASSOC ", 6) == 0) {
|
||||
test_driver_assoc(drv, &from, fromlen, buf + 6);
|
||||
} else if (strcmp(buf, "DISASSOC") == 0) {
|
||||
test_driver_disassoc(drv, &from, fromlen);
|
||||
} else if (strncmp(buf, "EAPOL ", 6) == 0) {
|
||||
test_driver_eapol(drv, &from, fromlen, buf + 6, res - 6);
|
||||
} else {
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "Unknown test_socket command",
|
||||
(u8 *) buf, res);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int test_driver_set_generic_elem(void *priv,
|
||||
const u8 *elem, size_t elem_len)
|
||||
{
|
||||
struct test_driver_data *drv = priv;
|
||||
|
||||
free(drv->ie);
|
||||
drv->ie = malloc(elem_len);
|
||||
if (drv->ie) {
|
||||
memcpy(drv->ie, elem, elem_len);
|
||||
drv->ielen = elem_len;
|
||||
return 0;
|
||||
} else {
|
||||
drv->ielen = 0;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int test_driver_sta_deauth(void *priv, u8 *addr, int reason)
|
||||
{
|
||||
struct test_driver_data *drv = priv;
|
||||
struct test_client_socket *cli;
|
||||
|
||||
if (drv->test_socket < 0)
|
||||
return -1;
|
||||
|
||||
cli = drv->cli;
|
||||
while (cli) {
|
||||
if (memcmp(cli->addr, addr, ETH_ALEN) == 0)
|
||||
break;
|
||||
cli = cli->next;
|
||||
}
|
||||
|
||||
if (!cli)
|
||||
return -1;
|
||||
|
||||
return sendto(drv->test_socket, "DEAUTH", 6, 0,
|
||||
(struct sockaddr *) &cli->un, cli->unlen);
|
||||
}
|
||||
|
||||
|
||||
static int test_driver_sta_disassoc(void *priv, u8 *addr, int reason)
|
||||
{
|
||||
struct test_driver_data *drv = priv;
|
||||
struct test_client_socket *cli;
|
||||
|
||||
if (drv->test_socket < 0)
|
||||
return -1;
|
||||
|
||||
cli = drv->cli;
|
||||
while (cli) {
|
||||
if (memcmp(cli->addr, addr, ETH_ALEN) == 0)
|
||||
break;
|
||||
cli = cli->next;
|
||||
}
|
||||
|
||||
if (!cli)
|
||||
return -1;
|
||||
|
||||
return sendto(drv->test_socket, "DISASSOC", 8, 0,
|
||||
(struct sockaddr *) &cli->un, cli->unlen);
|
||||
}
|
||||
|
||||
|
||||
static int test_driver_init(struct hostapd_data *hapd)
|
||||
{
|
||||
struct test_driver_data *drv;
|
||||
struct sockaddr_un addr;
|
||||
|
||||
drv = malloc(sizeof(struct test_driver_data));
|
||||
if (drv == NULL) {
|
||||
@ -50,6 +418,43 @@ static int test_driver_init(struct hostapd_data *hapd)
|
||||
drv->ops = test_driver_ops;
|
||||
drv->hapd = hapd;
|
||||
|
||||
/* Generate a MAC address to help testing with multiple APs */
|
||||
hapd->own_addr[0] = 0x02; /* locally administered */
|
||||
sha1_prf(hapd->conf->iface, strlen(hapd->conf->iface),
|
||||
"hostapd test bssid generation",
|
||||
hapd->conf->ssid, hapd->conf->ssid_len,
|
||||
hapd->own_addr + 1, ETH_ALEN - 1);
|
||||
|
||||
if (hapd->conf->test_socket) {
|
||||
if (strlen(hapd->conf->test_socket) >= sizeof(addr.sun_path)) {
|
||||
printf("Too long test_socket path\n");
|
||||
free(drv);
|
||||
return -1;
|
||||
}
|
||||
drv->test_socket = socket(PF_UNIX, SOCK_DGRAM, 0);
|
||||
if (drv->test_socket < 0) {
|
||||
perror("socket(PF_UNIX)");
|
||||
free(drv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sun_family = AF_UNIX;
|
||||
strncpy(addr.sun_path, hapd->conf->test_socket,
|
||||
sizeof(addr.sun_path));
|
||||
if (bind(drv->test_socket, (struct sockaddr *) &addr,
|
||||
sizeof(addr)) < 0) {
|
||||
perror("bind(PF_UNIX)");
|
||||
close(drv->test_socket);
|
||||
unlink(hapd->conf->test_socket);
|
||||
free(drv);
|
||||
return -1;
|
||||
}
|
||||
eloop_register_read_sock(drv->test_socket,
|
||||
test_driver_receive_unix, drv, NULL);
|
||||
} else
|
||||
drv->test_socket = -1;
|
||||
|
||||
hapd->driver = &drv->ops;
|
||||
return 0;
|
||||
}
|
||||
@ -58,9 +463,24 @@ static int test_driver_init(struct hostapd_data *hapd)
|
||||
static void test_driver_deinit(void *priv)
|
||||
{
|
||||
struct test_driver_data *drv = priv;
|
||||
struct test_client_socket *cli, *prev;
|
||||
|
||||
cli = drv->cli;
|
||||
while (cli) {
|
||||
prev = cli;
|
||||
cli = cli->next;
|
||||
free(prev);
|
||||
}
|
||||
|
||||
if (drv->test_socket >= 0) {
|
||||
eloop_unregister_read_sock(drv->test_socket);
|
||||
close(drv->test_socket);
|
||||
unlink(drv->hapd->conf->test_socket);
|
||||
}
|
||||
|
||||
drv->hapd->driver = NULL;
|
||||
|
||||
free(drv->ie);
|
||||
free(drv);
|
||||
}
|
||||
|
||||
@ -69,6 +489,10 @@ static const struct driver_ops test_driver_ops = {
|
||||
.name = "test",
|
||||
.init = test_driver_init,
|
||||
.deinit = test_driver_deinit,
|
||||
.send_eapol = test_driver_send_eapol,
|
||||
.set_generic_elem = test_driver_set_generic_elem,
|
||||
.sta_deauth = test_driver_sta_deauth,
|
||||
.sta_disassoc = test_driver_sta_disassoc,
|
||||
};
|
||||
|
||||
|
||||
|
@ -51,6 +51,7 @@ struct wired_driver_data {
|
||||
|
||||
int sock; /* raw packet socket for driver access */
|
||||
int dhcp_sock; /* socket for dhcp packets */
|
||||
int use_pae_group_addr;
|
||||
};
|
||||
|
||||
static const struct driver_ops wired_driver_ops;
|
||||
@ -95,7 +96,7 @@ static void wired_possible_new_sta(struct hostapd_data *hapd, u8 *addr)
|
||||
MACSTR " - adding a new STA\n", MAC2STR(addr));
|
||||
sta = ap_sta_add(hapd, addr);
|
||||
if (sta) {
|
||||
hostapd_new_assoc_sta(hapd, sta);
|
||||
hostapd_new_assoc_sta(hapd, sta, 0);
|
||||
accounting_sta_get_id(hapd, sta);
|
||||
} else {
|
||||
HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Failed to add STA entry "
|
||||
@ -309,7 +310,7 @@ static int wired_send_eapol(void *priv, u8 *addr,
|
||||
u8 *data, size_t data_len, int encrypt)
|
||||
{
|
||||
struct wired_driver_data *drv = priv;
|
||||
|
||||
u8 pae_group_addr[ETH_ALEN] = WIRED_EAPOL_MULTICAST_GROUP;
|
||||
struct ieee8023_hdr *hdr;
|
||||
size_t len;
|
||||
u8 *pos;
|
||||
@ -324,7 +325,8 @@ static int wired_send_eapol(void *priv, u8 *addr,
|
||||
}
|
||||
|
||||
memset(hdr, 0, len);
|
||||
memcpy(hdr->dest, addr, ETH_ALEN);
|
||||
memcpy(hdr->dest, drv->use_pae_group_addr ? pae_group_addr : addr,
|
||||
ETH_ALEN);
|
||||
memcpy(hdr->src, drv->hapd->own_addr, ETH_ALEN);
|
||||
hdr->ethertype = htons(ETH_P_PAE);
|
||||
|
||||
@ -357,6 +359,7 @@ static int wired_driver_init(struct hostapd_data *hapd)
|
||||
memset(drv, 0, sizeof(*drv));
|
||||
drv->ops = wired_driver_ops;
|
||||
drv->hapd = hapd;
|
||||
drv->use_pae_group_addr = hapd->conf->use_pae_group_addr;
|
||||
|
||||
if (wired_init_sockets(drv))
|
||||
return -1;
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "sta_info.h"
|
||||
#include "eap_i.h"
|
||||
|
||||
#define EAP_MAX_AUTH_ROUNDS 50
|
||||
|
||||
extern const struct eap_method eap_method_identity;
|
||||
#ifdef EAP_MD5
|
||||
@ -50,6 +51,12 @@ extern const struct eap_method eap_method_ttls;
|
||||
#ifdef EAP_SIM
|
||||
extern const struct eap_method eap_method_sim;
|
||||
#endif /* EAP_SIM */
|
||||
#ifdef EAP_PAX
|
||||
extern const struct eap_method eap_method_pax;
|
||||
#endif /* EAP_PAX */
|
||||
#ifdef EAP_PSK
|
||||
extern const struct eap_method eap_method_psk;
|
||||
#endif /* EAP_PSK */
|
||||
|
||||
static const struct eap_method *eap_methods[] =
|
||||
{
|
||||
@ -78,6 +85,12 @@ static const struct eap_method *eap_methods[] =
|
||||
#ifdef EAP_SIM
|
||||
&eap_method_sim,
|
||||
#endif /* EAP_SIM */
|
||||
#ifdef EAP_PAX
|
||||
&eap_method_pax,
|
||||
#endif /* EAP_PAX */
|
||||
#ifdef EAP_PSK
|
||||
&eap_method_psk,
|
||||
#endif /* EAP_PSK */
|
||||
};
|
||||
#define NUM_EAP_METHODS (sizeof(eap_methods) / sizeof(eap_methods[0]))
|
||||
|
||||
@ -197,6 +210,7 @@ int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len,
|
||||
SM_STATE(EAP, DISABLED)
|
||||
{
|
||||
SM_ENTRY(EAP, DISABLED);
|
||||
sm->num_rounds = 0;
|
||||
}
|
||||
|
||||
|
||||
@ -232,6 +246,7 @@ SM_STATE(EAP, INITIALIZE)
|
||||
sm->currentId = sm->respId;
|
||||
}
|
||||
}
|
||||
sm->num_rounds = 0;
|
||||
}
|
||||
|
||||
|
||||
@ -288,6 +303,7 @@ SM_STATE(EAP, RECEIVED)
|
||||
|
||||
/* parse rxResp, respId, respMethod */
|
||||
eap_sm_parseEapResp(sm, sm->eapRespData, sm->eapRespDataLen);
|
||||
sm->num_rounds++;
|
||||
}
|
||||
|
||||
|
||||
@ -503,7 +519,15 @@ SM_STEP(EAP)
|
||||
SM_ENTER_GLOBAL(EAP, INITIALIZE);
|
||||
else if (!eapol_get_bool(sm, EAPOL_portEnabled))
|
||||
SM_ENTER_GLOBAL(EAP, DISABLED);
|
||||
else switch (sm->EAP_state) {
|
||||
else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) {
|
||||
if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) {
|
||||
wpa_printf(MSG_DEBUG, "EAP: more than %d "
|
||||
"authentication rounds - abort",
|
||||
EAP_MAX_AUTH_ROUNDS);
|
||||
sm->num_rounds++;
|
||||
SM_ENTER_GLOBAL(EAP, FAILURE);
|
||||
}
|
||||
} else switch (sm->EAP_state) {
|
||||
case EAP_INITIALIZE:
|
||||
if (sm->backend_auth) {
|
||||
if (!sm->rxResp)
|
||||
@ -909,3 +933,12 @@ void eap_sm_deinit(struct eap_sm *sm)
|
||||
eap_user_free(sm->user);
|
||||
free(sm);
|
||||
}
|
||||
|
||||
|
||||
void eap_sm_notify_cached(struct eap_sm *sm)
|
||||
{
|
||||
if (sm == NULL)
|
||||
return;
|
||||
|
||||
sm->EAP_state = EAP_SUCCESS;
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ struct eapol_callbacks {
|
||||
size_t eapKeyDataLen);
|
||||
int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
|
||||
int phase2, struct eap_user *user);
|
||||
const char * (*get_eap_req_id_text)(void *ctx, size_t *len);
|
||||
};
|
||||
|
||||
struct eap_config {
|
||||
@ -39,7 +40,7 @@ struct eap_config {
|
||||
};
|
||||
|
||||
|
||||
#ifdef EAP_AUTHENTICATOR
|
||||
#ifdef EAP_SERVER
|
||||
|
||||
struct eap_sm * eap_sm_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
|
||||
struct eap_config *eap_conf);
|
||||
@ -48,8 +49,9 @@ int eap_sm_step(struct eap_sm *sm);
|
||||
u8 eap_get_type(const char *name);
|
||||
void eap_set_eapRespData(struct eap_sm *sm, const u8 *eapRespData,
|
||||
size_t eapRespDataLen);
|
||||
void eap_sm_notify_cached(struct eap_sm *sm);
|
||||
|
||||
#else /* EAP_AUTHENTICATOR */
|
||||
#else /* EAP_SERVER */
|
||||
|
||||
static inline struct eap_sm * eap_sm_init(void *eapol_ctx,
|
||||
struct eapol_callbacks *eapol_cb,
|
||||
@ -78,6 +80,10 @@ static inline void eap_set_eapRespData(struct eap_sm *sm,
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* EAP_AUTHENTICATOR */
|
||||
static inline void eap_sm_notify_cached(struct eap_sm *sm)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* EAP_SERVER */
|
||||
|
||||
#endif /* EAP_H */
|
||||
|
@ -1,3 +1,17 @@
|
||||
/*
|
||||
* WPA Supplicant/hostapd / Shared EAP definitions
|
||||
* Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#ifndef EAP_DEFS_H
|
||||
#define EAP_DEFS_H
|
||||
|
||||
@ -6,7 +20,7 @@
|
||||
struct eap_hdr {
|
||||
u8 code;
|
||||
u8 identifier;
|
||||
u16 length; /* including code and identifier */
|
||||
u16 length; /* including code and identifier; network byte order */
|
||||
/* followed by length-4 octets of data */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
@ -18,12 +32,12 @@ enum { EAP_CODE_REQUEST = 1, EAP_CODE_RESPONSE = 2, EAP_CODE_SUCCESS = 3,
|
||||
|
||||
typedef enum {
|
||||
EAP_TYPE_NONE = 0,
|
||||
EAP_TYPE_IDENTITY = 1,
|
||||
EAP_TYPE_NOTIFICATION = 2,
|
||||
EAP_TYPE_NAK = 3 /* Response only */,
|
||||
EAP_TYPE_MD5 = 4,
|
||||
EAP_TYPE_OTP = 5 /* RFC 2284 */,
|
||||
EAP_TYPE_GTC = 6, /* RFC 2284 */
|
||||
EAP_TYPE_IDENTITY = 1 /* RFC 3748 */,
|
||||
EAP_TYPE_NOTIFICATION = 2 /* RFC 3748 */,
|
||||
EAP_TYPE_NAK = 3 /* Response only, RFC 3748 */,
|
||||
EAP_TYPE_MD5 = 4, /* RFC 3748 */
|
||||
EAP_TYPE_OTP = 5 /* RFC 3748 */,
|
||||
EAP_TYPE_GTC = 6, /* RFC 3748 */
|
||||
EAP_TYPE_TLS = 13 /* RFC 2716 */,
|
||||
EAP_TYPE_LEAP = 17 /* Cisco proprietary */,
|
||||
EAP_TYPE_SIM = 18 /* draft-haverinen-pppext-eap-sim-12.txt */,
|
||||
@ -33,9 +47,10 @@ typedef enum {
|
||||
EAP_TYPE_MSCHAPV2 = 26 /* draft-kamath-pppext-eap-mschapv2-00.txt */,
|
||||
EAP_TYPE_TLV = 33 /* draft-josefsson-pppext-eap-tls-eap-07.txt */,
|
||||
EAP_TYPE_FAST = 43 /* draft-cam-winget-eap-fast-00.txt */,
|
||||
EAP_TYPE_PAX = 46, /* draft-clancy-eap-pax-04.txt */
|
||||
EAP_TYPE_EXPANDED_NAK = 254 /* RFC 3748 */,
|
||||
EAP_TYPE_PSK = 255 /* EXPERIMENTAL - type not yet allocated
|
||||
* draft-bersani-eap-psk-03 */
|
||||
* draft-bersani-eap-psk-09 */
|
||||
} EapType;
|
||||
|
||||
#endif /* EAP_DEFS_H */
|
||||
|
@ -100,6 +100,8 @@ struct eap_sm {
|
||||
void *eap_sim_db_priv;
|
||||
Boolean backend_auth;
|
||||
Boolean update_user;
|
||||
|
||||
int num_rounds;
|
||||
};
|
||||
|
||||
const struct eap_method * eap_sm_get_eap_methods(int method);
|
||||
|
@ -66,8 +66,17 @@ static u8 * eap_identity_buildReq(struct eap_sm *sm, void *priv, int id,
|
||||
struct eap_identity_data *data = priv;
|
||||
struct eap_hdr *req;
|
||||
u8 *pos;
|
||||
const char *req_data;
|
||||
size_t req_data_len;
|
||||
|
||||
*reqDataLen = sizeof(*req) + 1;
|
||||
if (sm->eapol_cb->get_eap_req_id_text) {
|
||||
req_data = sm->eapol_cb->get_eap_req_id_text(sm->eapol_ctx,
|
||||
&req_data_len);
|
||||
} else {
|
||||
req_data = NULL;
|
||||
req_data_len = 0;
|
||||
}
|
||||
*reqDataLen = sizeof(*req) + 1 + req_data_len;
|
||||
req = malloc(*reqDataLen);
|
||||
if (req == NULL) {
|
||||
wpa_printf(MSG_ERROR, "EAP-Identity: Failed to allocate "
|
||||
@ -80,7 +89,9 @@ static u8 * eap_identity_buildReq(struct eap_sm *sm, void *priv, int id,
|
||||
req->identifier = id;
|
||||
req->length = htons(*reqDataLen);
|
||||
pos = (u8 *) (req + 1);
|
||||
*pos = EAP_TYPE_IDENTITY;
|
||||
*pos++ = EAP_TYPE_IDENTITY;
|
||||
if (req_data)
|
||||
memcpy(pos, req_data, req_data_len);
|
||||
|
||||
return (u8 *) req;
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "common.h"
|
||||
#include "eap_i.h"
|
||||
#include "md5.h"
|
||||
#include "crypto.h"
|
||||
|
||||
|
||||
#define CHALLENGE_LEN 16
|
||||
@ -122,7 +123,8 @@ static void eap_md5_process(struct eap_sm *sm, void *priv,
|
||||
struct eap_md5_data *data = priv;
|
||||
struct eap_hdr *resp;
|
||||
u8 *pos;
|
||||
MD5_CTX context;
|
||||
const u8 *addr[3];
|
||||
size_t len[3];
|
||||
u8 hash[MD5_MAC_LEN];
|
||||
|
||||
if (sm->user == NULL || sm->user->password == NULL) {
|
||||
@ -136,11 +138,13 @@ static void eap_md5_process(struct eap_sm *sm, void *priv,
|
||||
pos += 2; /* Skip type and len */
|
||||
wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Response", pos, MD5_MAC_LEN);
|
||||
|
||||
MD5Init(&context);
|
||||
MD5Update(&context, &resp->identifier, 1);
|
||||
MD5Update(&context, sm->user->password, sm->user->password_len);
|
||||
MD5Update(&context, data->challenge, CHALLENGE_LEN);
|
||||
MD5Final(hash, &context);
|
||||
addr[0] = &resp->identifier;
|
||||
len[0] = 1;
|
||||
addr[1] = sm->user->password;
|
||||
len[1] = sm->user->password_len;
|
||||
addr[2] = data->challenge;
|
||||
len[2] = CHALLENGE_LEN;
|
||||
md5_vector(3, addr, len, hash);
|
||||
|
||||
if (memcmp(hash, pos, MD5_MAC_LEN) == 0) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-MD5: Done - Success");
|
||||
|
519
contrib/hostapd/eap_pax.c
Normal file
519
contrib/hostapd/eap_pax.c
Normal file
@ -0,0 +1,519 @@
|
||||
/*
|
||||
* hostapd / EAP-PAX (draft-clancy-eap-pax-04.txt) server
|
||||
* 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 <netinet/in.h>
|
||||
|
||||
#include "hostapd.h"
|
||||
#include "common.h"
|
||||
#include "eap_i.h"
|
||||
#include "eap_pax_common.h"
|
||||
|
||||
/*
|
||||
* Note: only PAX_STD subprotocol is currently supported
|
||||
*/
|
||||
|
||||
struct eap_pax_data {
|
||||
enum { PAX_STD_1, PAX_STD_3, SUCCESS, FAILURE } state;
|
||||
u8 mac_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;
|
||||
u8 ak[EAP_PAX_AK_LEN];
|
||||
u8 mk[EAP_PAX_MK_LEN];
|
||||
u8 ck[EAP_PAX_CK_LEN];
|
||||
u8 ick[EAP_PAX_ICK_LEN];
|
||||
int keys_set;
|
||||
char *cid;
|
||||
size_t cid_len;
|
||||
};
|
||||
|
||||
|
||||
static void * eap_pax_init(struct eap_sm *sm)
|
||||
{
|
||||
struct eap_pax_data *data;
|
||||
|
||||
data = malloc(sizeof(*data));
|
||||
if (data == NULL)
|
||||
return data;
|
||||
memset(data, 0, sizeof(*data));
|
||||
data->state = PAX_STD_1;
|
||||
/*
|
||||
* TODO: make this configurable once EAP_PAX_MAC_AES_CBC_MAC_128 is
|
||||
* supported
|
||||
*/
|
||||
data->mac_id = EAP_PAX_MAC_HMAC_SHA1_128;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
static void eap_pax_reset(struct eap_sm *sm, void *priv)
|
||||
{
|
||||
struct eap_pax_data *data = priv;
|
||||
free(data->cid);
|
||||
free(data);
|
||||
}
|
||||
|
||||
|
||||
static u8 * eap_pax_build_std_1(struct eap_sm *sm,
|
||||
struct eap_pax_data *data,
|
||||
int id, size_t *reqDataLen)
|
||||
{
|
||||
struct eap_pax_hdr *req;
|
||||
u8 *pos;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-1 (sending)");
|
||||
|
||||
if (hostapd_get_rand(data->rand.r.x, EAP_PAX_RAND_LEN)) {
|
||||
wpa_printf(MSG_ERROR, "EAP-PAX: Failed to get random data");
|
||||
data->state = FAILURE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*reqDataLen = sizeof(*req) + 2 + EAP_PAX_RAND_LEN + EAP_PAX_ICV_LEN;
|
||||
req = malloc(*reqDataLen);
|
||||
if (req == NULL) {
|
||||
wpa_printf(MSG_ERROR, "EAP-PAX: Failed to allocate memory "
|
||||
"request");
|
||||
data->state = FAILURE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
req->code = EAP_CODE_REQUEST;
|
||||
req->identifier = id;
|
||||
req->length = htons(*reqDataLen);
|
||||
req->type = EAP_TYPE_PAX;
|
||||
req->op_code = EAP_PAX_OP_STD_1;
|
||||
req->flags = 0;
|
||||
req->mac_id = data->mac_id;
|
||||
req->dh_group_id = EAP_PAX_DH_GROUP_NONE;
|
||||
req->public_key_id = EAP_PAX_PUBLIC_KEY_NONE;
|
||||
pos = (u8 *) (req + 1);
|
||||
*pos++ = 0;
|
||||
*pos++ = EAP_PAX_RAND_LEN;
|
||||
memcpy(pos, data->rand.r.x, EAP_PAX_RAND_LEN);
|
||||
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: A = X (server rand)",
|
||||
pos, EAP_PAX_RAND_LEN);
|
||||
pos += EAP_PAX_RAND_LEN;
|
||||
|
||||
eap_pax_mac(data->mac_id, (u8 *) "", 0,
|
||||
(u8 *) req, *reqDataLen - EAP_PAX_ICV_LEN,
|
||||
NULL, 0, NULL, 0, pos);
|
||||
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", pos, EAP_PAX_ICV_LEN);
|
||||
pos += EAP_PAX_ICV_LEN;
|
||||
|
||||
return (u8 *) req;
|
||||
}
|
||||
|
||||
|
||||
static u8 * eap_pax_build_std_3(struct eap_sm *sm,
|
||||
struct eap_pax_data *data,
|
||||
int id, size_t *reqDataLen)
|
||||
{
|
||||
struct eap_pax_hdr *req;
|
||||
u8 *pos;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-3 (sending)");
|
||||
|
||||
*reqDataLen = sizeof(*req) + 2 + EAP_PAX_MAC_LEN + EAP_PAX_ICV_LEN;
|
||||
req = malloc(*reqDataLen);
|
||||
if (req == NULL) {
|
||||
wpa_printf(MSG_ERROR, "EAP-PAX: Failed to allocate memory "
|
||||
"request");
|
||||
data->state = FAILURE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
req->code = EAP_CODE_REQUEST;
|
||||
req->identifier = id;
|
||||
req->length = htons(*reqDataLen);
|
||||
req->type = EAP_TYPE_PAX;
|
||||
req->op_code = EAP_PAX_OP_STD_3;
|
||||
req->flags = 0;
|
||||
req->mac_id = data->mac_id;
|
||||
req->dh_group_id = EAP_PAX_DH_GROUP_NONE;
|
||||
req->public_key_id = EAP_PAX_PUBLIC_KEY_NONE;
|
||||
pos = (u8 *) (req + 1);
|
||||
*pos++ = 0;
|
||||
*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, pos);
|
||||
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(B, CID)",
|
||||
pos, EAP_PAX_MAC_LEN);
|
||||
pos += EAP_PAX_MAC_LEN;
|
||||
|
||||
eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
|
||||
(u8 *) req, *reqDataLen - EAP_PAX_ICV_LEN,
|
||||
NULL, 0, NULL, 0, pos);
|
||||
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", pos, EAP_PAX_ICV_LEN);
|
||||
pos += EAP_PAX_ICV_LEN;
|
||||
|
||||
return (u8 *) req;
|
||||
}
|
||||
|
||||
|
||||
static u8 * eap_pax_buildReq(struct eap_sm *sm, void *priv, int id,
|
||||
size_t *reqDataLen)
|
||||
{
|
||||
struct eap_pax_data *data = priv;
|
||||
|
||||
switch (data->state) {
|
||||
case PAX_STD_1:
|
||||
return eap_pax_build_std_1(sm, data, id, reqDataLen);
|
||||
case PAX_STD_3:
|
||||
return eap_pax_build_std_3(sm, data, id, reqDataLen);
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, "EAP-PAX: Unknown state %d in buildReq",
|
||||
data->state);
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static Boolean eap_pax_check(struct eap_sm *sm, void *priv,
|
||||
u8 *respData, size_t respDataLen)
|
||||
{
|
||||
struct eap_pax_data *data = priv;
|
||||
struct eap_pax_hdr *resp;
|
||||
size_t len;
|
||||
u8 icvbuf[EAP_PAX_ICV_LEN], *icv;
|
||||
|
||||
resp = (struct eap_pax_hdr *) respData;
|
||||
if (respDataLen < sizeof(*resp) || resp->type != EAP_TYPE_PAX ||
|
||||
(len = ntohs(resp->length)) > respDataLen ||
|
||||
len < sizeof(*resp) + EAP_PAX_ICV_LEN) {
|
||||
wpa_printf(MSG_INFO, "EAP-PAX: Invalid frame");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
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",
|
||||
resp->op_code, resp->flags, resp->mac_id, resp->dh_group_id,
|
||||
resp->public_key_id);
|
||||
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: received payload",
|
||||
(u8 *) (resp + 1), len - sizeof(*resp) - EAP_PAX_ICV_LEN);
|
||||
|
||||
if (data->state == PAX_STD_1 &&
|
||||
resp->op_code != EAP_PAX_OP_STD_2) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-PAX: Expected PAX_STD-2 - "
|
||||
"ignore op %d", resp->op_code);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (data->state == PAX_STD_3 &&
|
||||
resp->op_code != EAP_PAX_OP_ACK) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-PAX: Expected PAX-ACK - "
|
||||
"ignore op %d", resp->op_code);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (resp->op_code != EAP_PAX_OP_STD_2 &&
|
||||
resp->op_code != EAP_PAX_OP_ACK) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-PAX: Unknown op_code 0x%x",
|
||||
resp->op_code);
|
||||
}
|
||||
|
||||
if (data->mac_id != resp->mac_id) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-PAX: Expected MAC ID 0x%x, "
|
||||
"received 0x%x", data->mac_id, resp->mac_id);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (resp->dh_group_id != EAP_PAX_DH_GROUP_NONE) {
|
||||
wpa_printf(MSG_INFO, "EAP-PAX: Expected DH Group ID 0x%x, "
|
||||
"received 0x%x", EAP_PAX_DH_GROUP_NONE,
|
||||
resp->dh_group_id);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (resp->public_key_id != EAP_PAX_PUBLIC_KEY_NONE) {
|
||||
wpa_printf(MSG_INFO, "EAP-PAX: Expected Public Key ID 0x%x, "
|
||||
"received 0x%x", EAP_PAX_PUBLIC_KEY_NONE,
|
||||
resp->public_key_id);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (resp->flags & EAP_PAX_FLAGS_MF) {
|
||||
/* TODO: add support for reassembling fragments */
|
||||
wpa_printf(MSG_INFO, "EAP-PAX: fragmentation not supported");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (resp->flags & EAP_PAX_FLAGS_CE) {
|
||||
wpa_printf(MSG_INFO, "EAP-PAX: Unexpected CE flag");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (data->keys_set) {
|
||||
if (len - sizeof(*resp) < EAP_PAX_ICV_LEN) {
|
||||
wpa_printf(MSG_INFO, "EAP-PAX: No ICV in the packet");
|
||||
return TRUE;
|
||||
}
|
||||
icv = respData + len - EAP_PAX_ICV_LEN;
|
||||
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", icv, EAP_PAX_ICV_LEN);
|
||||
eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
|
||||
respData, len - EAP_PAX_ICV_LEN, NULL, 0, NULL, 0,
|
||||
icvbuf);
|
||||
if (memcmp(icvbuf, icv, EAP_PAX_ICV_LEN) != 0) {
|
||||
wpa_printf(MSG_INFO, "EAP-PAX: Invalid ICV");
|
||||
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected ICV",
|
||||
icvbuf, EAP_PAX_ICV_LEN);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
static void eap_pax_process_std_2(struct eap_sm *sm,
|
||||
struct eap_pax_data *data,
|
||||
u8 *respData, size_t respDataLen)
|
||||
{
|
||||
struct eap_pax_hdr *resp;
|
||||
u8 *pos, mac[EAP_PAX_MAC_LEN], icvbuf[EAP_PAX_ICV_LEN];
|
||||
size_t len, left;
|
||||
int i;
|
||||
|
||||
if (data->state != PAX_STD_1)
|
||||
return;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "EAP-PAX: Received PAX_STD-2");
|
||||
|
||||
resp = (struct eap_pax_hdr *) respData;
|
||||
len = ntohs(resp->length);
|
||||
pos = (u8 *) (resp + 1);
|
||||
left = len - sizeof(*resp);
|
||||
|
||||
if (left < 2 + EAP_PAX_RAND_LEN ||
|
||||
((pos[0] << 8) | pos[1]) != EAP_PAX_RAND_LEN) {
|
||||
wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (B)");
|
||||
return;
|
||||
}
|
||||
pos += 2;
|
||||
left -= 2;
|
||||
memcpy(data->rand.r.y, pos, EAP_PAX_RAND_LEN);
|
||||
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Y (client rand)",
|
||||
data->rand.r.y, EAP_PAX_RAND_LEN);
|
||||
pos += EAP_PAX_RAND_LEN;
|
||||
left -= EAP_PAX_RAND_LEN;
|
||||
|
||||
if (left < 2 || 2 + ((pos[0] << 8) | pos[1]) > left) {
|
||||
wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (CID)");
|
||||
return;
|
||||
}
|
||||
data->cid_len = (pos[0] << 8) | pos[1];
|
||||
free(data->cid);
|
||||
data->cid = malloc(data->cid_len);
|
||||
if (data->cid == NULL) {
|
||||
wpa_printf(MSG_INFO, "EAP-PAX: Failed to allocate memory for "
|
||||
"CID");
|
||||
return;
|
||||
}
|
||||
memcpy (data->cid, pos + 2, data->cid_len);
|
||||
pos += 2 + data->cid_len;
|
||||
left -= 2 + data->cid_len;
|
||||
wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-PAX: CID",
|
||||
(u8 *) data->cid, data->cid_len);
|
||||
|
||||
if (left < 2 + EAP_PAX_MAC_LEN ||
|
||||
((pos[0] << 8) | pos[1]) != EAP_PAX_MAC_LEN) {
|
||||
wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (MAC_CK)");
|
||||
return;
|
||||
}
|
||||
pos += 2;
|
||||
left -= 2;
|
||||
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(A, B, CID)",
|
||||
pos, EAP_PAX_MAC_LEN);
|
||||
|
||||
if (eap_user_get(sm, (u8 *) data->cid, data->cid_len, 0) < 0) {
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "EAP-PAX: unknown CID",
|
||||
(u8 *) data->cid, data->cid_len);
|
||||
data->state = FAILURE;
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0;
|
||||
i < EAP_MAX_METHODS && sm->user->methods[i] != EAP_TYPE_NONE;
|
||||
i++) {
|
||||
if (sm->user->methods[i] == EAP_TYPE_PAX)
|
||||
break;
|
||||
}
|
||||
|
||||
if (sm->user->methods[i] != EAP_TYPE_PAX) {
|
||||
wpa_hexdump_ascii(MSG_DEBUG,
|
||||
"EAP-PAX: EAP-PAX not enabled for CID",
|
||||
(u8 *) data->cid, data->cid_len);
|
||||
data->state = FAILURE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (sm->user->password == NULL ||
|
||||
sm->user->password_len != EAP_PAX_AK_LEN) {
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "EAP-PAX: invalid password in "
|
||||
"user database for CID",
|
||||
(u8 *) data->cid, data->cid_len);
|
||||
data->state = FAILURE;
|
||||
return;
|
||||
}
|
||||
memcpy(data->ak, sm->user->password, EAP_PAX_AK_LEN);
|
||||
|
||||
if (eap_pax_initial_key_derivation(data->mac_id, data->ak,
|
||||
data->rand.e, data->mk, data->ck,
|
||||
data->ick) < 0) {
|
||||
wpa_printf(MSG_INFO, "EAP-PAX: Failed to complete initial "
|
||||
"key derivation");
|
||||
data->state = FAILURE;
|
||||
return;
|
||||
}
|
||||
data->keys_set = 1;
|
||||
|
||||
eap_pax_mac(data->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, mac);
|
||||
if (memcmp(mac, pos, EAP_PAX_MAC_LEN) != 0) {
|
||||
wpa_printf(MSG_INFO, "EAP-PAX: Invalid MAC_CK(A, B, CID) in "
|
||||
"PAX_STD-2");
|
||||
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected MAC_CK(A, B, CID)",
|
||||
mac, EAP_PAX_MAC_LEN);
|
||||
data->state = FAILURE;
|
||||
return;
|
||||
}
|
||||
|
||||
pos += EAP_PAX_MAC_LEN;
|
||||
left -= EAP_PAX_MAC_LEN;
|
||||
|
||||
if (left < EAP_PAX_ICV_LEN) {
|
||||
wpa_printf(MSG_INFO, "EAP-PAX: Too short ICV (%lu) in "
|
||||
"PAX_STD-2", (unsigned long) left);
|
||||
return;
|
||||
}
|
||||
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", pos, EAP_PAX_ICV_LEN);
|
||||
eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
|
||||
respData, len - EAP_PAX_ICV_LEN, NULL, 0, NULL, 0, icvbuf);
|
||||
if (memcmp(icvbuf, pos, EAP_PAX_ICV_LEN) != 0) {
|
||||
wpa_printf(MSG_INFO, "EAP-PAX: Invalid ICV in PAX_STD-2");
|
||||
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected ICV",
|
||||
icvbuf, EAP_PAX_ICV_LEN);
|
||||
return;
|
||||
}
|
||||
pos += EAP_PAX_ICV_LEN;
|
||||
left -= EAP_PAX_ICV_LEN;
|
||||
|
||||
if (left > 0) {
|
||||
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ignored extra payload",
|
||||
pos, left);
|
||||
}
|
||||
|
||||
data->state = PAX_STD_3;
|
||||
}
|
||||
|
||||
|
||||
static void eap_pax_process_ack(struct eap_sm *sm,
|
||||
struct eap_pax_data *data,
|
||||
u8 *respData, size_t respDataLen)
|
||||
{
|
||||
if (data->state != PAX_STD_3)
|
||||
return;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "EAP-PAX: Received PAX-ACK - authentication "
|
||||
"completed successfully");
|
||||
data->state = SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static void eap_pax_process(struct eap_sm *sm, void *priv,
|
||||
u8 *respData, size_t respDataLen)
|
||||
{
|
||||
struct eap_pax_data *data = priv;
|
||||
struct eap_pax_hdr *resp;
|
||||
|
||||
if (sm->user == NULL || sm->user->password == NULL) {
|
||||
wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Password not configured");
|
||||
data->state = FAILURE;
|
||||
return;
|
||||
}
|
||||
|
||||
resp = (struct eap_pax_hdr *) respData;
|
||||
|
||||
switch (resp->op_code) {
|
||||
case EAP_PAX_OP_STD_2:
|
||||
eap_pax_process_std_2(sm, data, respData, respDataLen);
|
||||
break;
|
||||
case EAP_PAX_OP_ACK:
|
||||
eap_pax_process_ack(sm, data, respData, respDataLen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static Boolean eap_pax_isDone(struct eap_sm *sm, void *priv)
|
||||
{
|
||||
struct eap_pax_data *data = priv;
|
||||
return data->state == SUCCESS || data->state == FAILURE;
|
||||
}
|
||||
|
||||
|
||||
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 != SUCCESS)
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
static Boolean eap_pax_isSuccess(struct eap_sm *sm, void *priv)
|
||||
{
|
||||
struct eap_pax_data *data = priv;
|
||||
return data->state == SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
const struct eap_method eap_method_pax =
|
||||
{
|
||||
.method = EAP_TYPE_PAX,
|
||||
.name = "PAX",
|
||||
.init = eap_pax_init,
|
||||
.reset = eap_pax_reset,
|
||||
.buildReq = eap_pax_buildReq,
|
||||
.check = eap_pax_check,
|
||||
.process = eap_pax_process,
|
||||
.isDone = eap_pax_isDone,
|
||||
.getKey = eap_pax_getKey,
|
||||
.isSuccess = eap_pax_isSuccess,
|
||||
};
|
152
contrib/hostapd/eap_pax_common.c
Normal file
152
contrib/hostapd/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/hostapd/eap_pax_common.h
Normal file
84
contrib/hostapd/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 */
|
@ -664,6 +664,12 @@ static void eap_peap_process(struct eap_sm *sm, void *priv,
|
||||
data->state, __func__);
|
||||
break;
|
||||
}
|
||||
|
||||
if (tls_connection_get_write_alerts(sm->ssl_ctx, data->ssl.conn) > 1) {
|
||||
wpa_printf(MSG_INFO, "EAP-PEAP: Locally detected fatal error "
|
||||
"in TLS processing");
|
||||
eap_peap_state(data, FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
458
contrib/hostapd/eap_psk.c
Normal file
458
contrib/hostapd/eap_psk.c
Normal file
@ -0,0 +1,458 @@
|
||||
/*
|
||||
* hostapd / EAP-PSK (draft-bersani-eap-psk-09.txt) server
|
||||
* 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.
|
||||
*
|
||||
* 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>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "hostapd.h"
|
||||
#include "common.h"
|
||||
#include "eap_i.h"
|
||||
#include "aes_wrap.h"
|
||||
#include "eap_psk_common.h"
|
||||
|
||||
|
||||
struct eap_psk_data {
|
||||
enum { PSK_1, PSK_3, SUCCESS, FAILURE } state;
|
||||
u8 rand_s[EAP_PSK_RAND_LEN];
|
||||
u8 rand_p[EAP_PSK_RAND_LEN];
|
||||
u8 *id_p, *id_s;
|
||||
size_t id_p_len, id_s_len;
|
||||
u8 ak[EAP_PSK_AK_LEN], kdk[EAP_PSK_KDK_LEN], tek[EAP_PSK_TEK_LEN];
|
||||
u8 msk[EAP_PSK_MSK_LEN];
|
||||
};
|
||||
|
||||
|
||||
static void * eap_psk_init(struct eap_sm *sm)
|
||||
{
|
||||
struct eap_psk_data *data;
|
||||
|
||||
data = malloc(sizeof(*data));
|
||||
if (data == NULL)
|
||||
return data;
|
||||
memset(data, 0, sizeof(*data));
|
||||
data->state = PSK_1;
|
||||
data->id_s = "hostapd";
|
||||
data->id_s_len = 7;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
static void eap_psk_reset(struct eap_sm *sm, void *priv)
|
||||
{
|
||||
struct eap_psk_data *data = priv;
|
||||
free(data->id_p);
|
||||
free(data);
|
||||
}
|
||||
|
||||
|
||||
static u8 * eap_psk_build_1(struct eap_sm *sm, struct eap_psk_data *data,
|
||||
int id, size_t *reqDataLen)
|
||||
{
|
||||
struct eap_psk_hdr_1 *req;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "EAP-PSK: PSK-1 (sending)");
|
||||
|
||||
if (hostapd_get_rand(data->rand_s, EAP_PSK_RAND_LEN)) {
|
||||
wpa_printf(MSG_ERROR, "EAP-PSK: Failed to get random data");
|
||||
data->state = FAILURE;
|
||||
return NULL;
|
||||
}
|
||||
wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: RAND_S (server rand)",
|
||||
data->rand_s, EAP_PSK_RAND_LEN);
|
||||
|
||||
*reqDataLen = sizeof(*req) + data->id_s_len;
|
||||
req = malloc(*reqDataLen);
|
||||
if (req == NULL) {
|
||||
wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory "
|
||||
"request");
|
||||
data->state = FAILURE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
req->code = EAP_CODE_REQUEST;
|
||||
req->identifier = id;
|
||||
req->length = htons(*reqDataLen);
|
||||
req->type = EAP_TYPE_PSK;
|
||||
req->flags = 0; /* T=0 */
|
||||
memcpy(req->rand_s, data->rand_s, EAP_PSK_RAND_LEN);
|
||||
memcpy((u8 *) (req + 1), data->id_s, data->id_s_len);
|
||||
|
||||
return (u8 *) req;
|
||||
}
|
||||
|
||||
|
||||
static u8 * eap_psk_build_3(struct eap_sm *sm, struct eap_psk_data *data,
|
||||
int id, size_t *reqDataLen)
|
||||
{
|
||||
struct eap_psk_hdr_3 *req;
|
||||
u8 *buf, *pchannel, nonce[16];
|
||||
size_t buflen;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "EAP-PSK: PSK-3 (sending)");
|
||||
|
||||
*reqDataLen = sizeof(*req) + 4 + 16 + 1;
|
||||
req = malloc(*reqDataLen);
|
||||
if (req == NULL) {
|
||||
wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory "
|
||||
"request");
|
||||
data->state = FAILURE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
req->code = EAP_CODE_REQUEST;
|
||||
req->identifier = id;
|
||||
req->length = htons(*reqDataLen);
|
||||
req->type = EAP_TYPE_PSK;
|
||||
req->flags = 2; /* T=2 */
|
||||
memcpy(req->rand_s, data->rand_s, EAP_PSK_RAND_LEN);
|
||||
|
||||
/* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */
|
||||
buflen = data->id_s_len + EAP_PSK_RAND_LEN;
|
||||
buf = malloc(buflen);
|
||||
if (buf == NULL) {
|
||||
data->state = FAILURE;
|
||||
return NULL;
|
||||
}
|
||||
memcpy(buf, data->id_s, data->id_s_len);
|
||||
memcpy(buf + data->id_s_len, data->rand_p, EAP_PSK_RAND_LEN);
|
||||
omac1_aes_128(data->ak, buf, buflen, req->mac_s);
|
||||
free(buf);
|
||||
|
||||
eap_psk_derive_keys(data->kdk, data->rand_p, data->tek, data->msk);
|
||||
wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: TEK", data->tek, EAP_PSK_TEK_LEN);
|
||||
wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: MSK", data->msk, EAP_PSK_MSK_LEN);
|
||||
|
||||
memset(nonce, 0, sizeof(nonce));
|
||||
pchannel = (u8 *) (req + 1);
|
||||
memcpy(pchannel, nonce + 12, 4);
|
||||
memset(pchannel + 4, 0, 16); /* Tag */
|
||||
pchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_SUCCESS << 6;
|
||||
wpa_hexdump(MSG_DEBUG, "EAP-PSK: PCHANNEL (plaintext)",
|
||||
pchannel, 4 + 16 + 1);
|
||||
aes_128_eax_encrypt(data->tek, nonce, sizeof(nonce), (u8 *) req, 22,
|
||||
pchannel + 4 + 16, 1, pchannel + 4);
|
||||
wpa_hexdump(MSG_DEBUG, "EAP-PSK: PCHANNEL (encrypted)",
|
||||
pchannel, 4 + 16 + 1);
|
||||
|
||||
return (u8 *) req;
|
||||
}
|
||||
|
||||
|
||||
static u8 * eap_psk_buildReq(struct eap_sm *sm, void *priv, int id,
|
||||
size_t *reqDataLen)
|
||||
{
|
||||
struct eap_psk_data *data = priv;
|
||||
|
||||
switch (data->state) {
|
||||
case PSK_1:
|
||||
return eap_psk_build_1(sm, data, id, reqDataLen);
|
||||
case PSK_3:
|
||||
return eap_psk_build_3(sm, data, id, reqDataLen);
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, "EAP-PSK: Unknown state %d in buildReq",
|
||||
data->state);
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static Boolean eap_psk_check(struct eap_sm *sm, void *priv,
|
||||
u8 *respData, size_t respDataLen)
|
||||
{
|
||||
struct eap_psk_data *data = priv;
|
||||
struct eap_psk_hdr *resp;
|
||||
size_t len;
|
||||
u8 t;
|
||||
|
||||
resp = (struct eap_psk_hdr *) respData;
|
||||
if (respDataLen < sizeof(*resp) || resp->type != EAP_TYPE_PSK ||
|
||||
(len = ntohs(resp->length)) > respDataLen ||
|
||||
len < sizeof(*resp)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PSK: Invalid frame");
|
||||
return TRUE;
|
||||
}
|
||||
t = resp->flags & 0x03;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "EAP-PSK: received frame: T=%d", t);
|
||||
|
||||
if (data->state == PSK_1 && t != 1) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-PSK: Expected PSK-2 - "
|
||||
"ignore T=%d", t);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (data->state == PSK_3 && t != 3) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-PSK: Expected PSK-4 - "
|
||||
"ignore T=%d", t);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if ((t == 1 && len < sizeof(struct eap_psk_hdr_2)) ||
|
||||
(t == 3 && len < sizeof(struct eap_psk_hdr_4))) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-PSK: Too short frame");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
static void eap_psk_process_2(struct eap_sm *sm,
|
||||
struct eap_psk_data *data,
|
||||
u8 *respData, size_t respDataLen)
|
||||
{
|
||||
struct eap_psk_hdr_2 *resp;
|
||||
u8 *pos, mac[EAP_PSK_MAC_LEN], *buf;
|
||||
size_t len, left, buflen;
|
||||
int i;
|
||||
|
||||
if (data->state != PSK_1)
|
||||
return;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "EAP-PSK: Received PSK-2");
|
||||
|
||||
resp = (struct eap_psk_hdr_2 *) respData;
|
||||
len = ntohs(resp->length);
|
||||
pos = (u8 *) (resp + 1);
|
||||
left = len - sizeof(*resp);
|
||||
|
||||
free(data->id_p);
|
||||
data->id_p = malloc(left);
|
||||
if (data->id_p == NULL) {
|
||||
wpa_printf(MSG_INFO, "EAP-PSK: Failed to allocate memory for "
|
||||
"ID_P");
|
||||
return;
|
||||
}
|
||||
memcpy(data->id_p, pos, left);
|
||||
data->id_p_len = left;
|
||||
wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-PSK: ID_P",
|
||||
data->id_p, data->id_p_len);
|
||||
|
||||
if (eap_user_get(sm, data->id_p, data->id_p_len, 0) < 0) {
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: unknown ID_P",
|
||||
data->id_p, data->id_p_len);
|
||||
data->state = FAILURE;
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0;
|
||||
i < EAP_MAX_METHODS && sm->user->methods[i] != EAP_TYPE_NONE;
|
||||
i++) {
|
||||
if (sm->user->methods[i] == EAP_TYPE_PSK)
|
||||
break;
|
||||
}
|
||||
|
||||
if (sm->user->methods[i] != EAP_TYPE_PSK) {
|
||||
wpa_hexdump_ascii(MSG_DEBUG,
|
||||
"EAP-PSK: EAP-PSK not enabled for ID_P",
|
||||
data->id_p, data->id_p_len);
|
||||
data->state = FAILURE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (sm->user->password == NULL ||
|
||||
sm->user->password_len != EAP_PSK_PSK_LEN) {
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: invalid password in "
|
||||
"user database for ID_P",
|
||||
data->id_p, data->id_p_len);
|
||||
data->state = FAILURE;
|
||||
return;
|
||||
}
|
||||
eap_psk_key_setup(sm->user->password, data->ak, data->kdk);
|
||||
wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: AK", data->ak, EAP_PSK_AK_LEN);
|
||||
wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: KDK", data->kdk, EAP_PSK_KDK_LEN);
|
||||
|
||||
wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: RAND_P (client rand)",
|
||||
resp->rand_p, EAP_PSK_RAND_LEN);
|
||||
memcpy(data->rand_p, resp->rand_p, EAP_PSK_RAND_LEN);
|
||||
|
||||
/* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */
|
||||
buflen = data->id_p_len + data->id_s_len + 2 * EAP_PSK_RAND_LEN;
|
||||
buf = malloc(buflen);
|
||||
if (buf == NULL) {
|
||||
data->state = FAILURE;
|
||||
return;
|
||||
}
|
||||
memcpy(buf, data->id_p, data->id_p_len);
|
||||
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);
|
||||
pos += EAP_PSK_RAND_LEN;
|
||||
memcpy(pos, data->rand_p, EAP_PSK_RAND_LEN);
|
||||
omac1_aes_128(data->ak, buf, buflen, mac);
|
||||
free(buf);
|
||||
wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_P", resp->mac_p, EAP_PSK_MAC_LEN);
|
||||
if (memcmp(mac, resp->mac_p, EAP_PSK_MAC_LEN) != 0) {
|
||||
wpa_printf(MSG_INFO, "EAP-PSK: Invalid MAC_P");
|
||||
wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: Expected MAC_P",
|
||||
mac, EAP_PSK_MAC_LEN);
|
||||
data->state = FAILURE;
|
||||
return;
|
||||
}
|
||||
|
||||
data->state = PSK_3;
|
||||
}
|
||||
|
||||
|
||||
static void eap_psk_process_4(struct eap_sm *sm,
|
||||
struct eap_psk_data *data,
|
||||
u8 *respData, size_t respDataLen)
|
||||
{
|
||||
struct eap_psk_hdr_4 *resp;
|
||||
u8 *pos, *decrypted, nonce[16], *tag;
|
||||
size_t left;
|
||||
|
||||
if (data->state != PSK_3)
|
||||
return;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "EAP-PSK: Received PSK-4");
|
||||
|
||||
resp = (struct eap_psk_hdr_4 *) respData;
|
||||
pos = (u8 *) (resp + 1);
|
||||
left = ntohs(resp->length) - sizeof(*resp);
|
||||
|
||||
wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: Encrypted PCHANNEL", pos, left);
|
||||
|
||||
if (left < 4 + 16 + 1) {
|
||||
wpa_printf(MSG_INFO, "EAP-PSK: Too short PCHANNEL data in "
|
||||
"PSK-4 (len=%lu, expected 21)",
|
||||
(unsigned long) left);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pos[0] == 0 && pos[1] == 0 && pos[2] == 0 && pos[3] == 0) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-PSK: Nonce did not increase");
|
||||
return;
|
||||
}
|
||||
|
||||
memset(nonce, 0, 12);
|
||||
memcpy(nonce + 12, pos, 4);
|
||||
pos += 4;
|
||||
left -= 4;
|
||||
tag = pos;
|
||||
pos += 16;
|
||||
left -= 16;
|
||||
|
||||
decrypted = malloc(left);
|
||||
if (decrypted == NULL)
|
||||
return;
|
||||
memcpy(decrypted, pos, left);
|
||||
|
||||
if (aes_128_eax_decrypt(data->tek, nonce, sizeof(nonce),
|
||||
respData, 22, decrypted, left, tag)) {
|
||||
wpa_printf(MSG_WARNING, "EAP-PSK: PCHANNEL decryption failed");
|
||||
free(decrypted);
|
||||
data->state = FAILURE;
|
||||
return;
|
||||
}
|
||||
wpa_hexdump(MSG_DEBUG, "EAP-PSK: Decrypted PCHANNEL message",
|
||||
decrypted, left);
|
||||
|
||||
/* Verify R flag */
|
||||
switch (decrypted[0] >> 6) {
|
||||
case EAP_PSK_R_FLAG_CONT:
|
||||
wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - CONT - unsupported");
|
||||
data->state = FAILURE;
|
||||
break;
|
||||
case EAP_PSK_R_FLAG_DONE_SUCCESS:
|
||||
wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_SUCCESS");
|
||||
data->state = SUCCESS;
|
||||
break;
|
||||
case EAP_PSK_R_FLAG_DONE_FAILURE:
|
||||
wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_FAILURE");
|
||||
data->state = FAILURE;
|
||||
break;
|
||||
}
|
||||
free(decrypted);
|
||||
}
|
||||
|
||||
|
||||
static void eap_psk_process(struct eap_sm *sm, void *priv,
|
||||
u8 *respData, size_t respDataLen)
|
||||
{
|
||||
struct eap_psk_data *data = priv;
|
||||
struct eap_psk_hdr *resp;
|
||||
|
||||
if (sm->user == NULL || sm->user->password == NULL) {
|
||||
wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Password not configured");
|
||||
data->state = FAILURE;
|
||||
return;
|
||||
}
|
||||
|
||||
resp = (struct eap_psk_hdr *) respData;
|
||||
|
||||
switch (resp->flags & 0x03) {
|
||||
case 1:
|
||||
eap_psk_process_2(sm, data, respData, respDataLen);
|
||||
break;
|
||||
case 3:
|
||||
eap_psk_process_4(sm, data, respData, respDataLen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static Boolean eap_psk_isDone(struct eap_sm *sm, void *priv)
|
||||
{
|
||||
struct eap_psk_data *data = priv;
|
||||
return data->state == SUCCESS || data->state == FAILURE;
|
||||
}
|
||||
|
||||
|
||||
static u8 * eap_psk_getKey(struct eap_sm *sm, void *priv, size_t *len)
|
||||
{
|
||||
struct eap_psk_data *data = priv;
|
||||
u8 *key;
|
||||
|
||||
if (data->state != SUCCESS)
|
||||
return NULL;
|
||||
|
||||
key = malloc(EAP_PSK_MSK_LEN);
|
||||
if (key == NULL)
|
||||
return NULL;
|
||||
memcpy(key, data->msk, EAP_PSK_MSK_LEN);
|
||||
*len = EAP_PSK_MSK_LEN;
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
static Boolean eap_psk_isSuccess(struct eap_sm *sm, void *priv)
|
||||
{
|
||||
struct eap_psk_data *data = priv;
|
||||
return data->state == SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
const struct eap_method eap_method_psk =
|
||||
{
|
||||
.method = EAP_TYPE_PSK,
|
||||
.name = "PSK",
|
||||
.init = eap_psk_init,
|
||||
.reset = eap_psk_reset,
|
||||
.buildReq = eap_psk_buildReq,
|
||||
.check = eap_psk_check,
|
||||
.process = eap_psk_process,
|
||||
.isDone = eap_psk_isDone,
|
||||
.getKey = eap_psk_getKey,
|
||||
.isSuccess = eap_psk_isSuccess,
|
||||
};
|
57
contrib/hostapd/eap_psk_common.c
Normal file
57
contrib/hostapd/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/hostapd/eap_psk_common.h
Normal file
92
contrib/hostapd/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 */
|
@ -19,7 +19,7 @@
|
||||
|
||||
#include "hostapd.h"
|
||||
#include "common.h"
|
||||
#include "sha1.h"
|
||||
#include "crypto.h"
|
||||
#include "eap_i.h"
|
||||
#include "eap_sim_common.h"
|
||||
#include "eap_sim_db.h"
|
||||
|
@ -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;
|
||||
|
@ -108,6 +108,7 @@ int eap_sim_db_get_gsm_triplets(void *priv, const u8 *identity,
|
||||
if (identity_len < 2 || identity[0] != '1') {
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
|
||||
identity, identity_len);
|
||||
fclose(f);
|
||||
return -1;
|
||||
}
|
||||
identity++;
|
||||
|
@ -191,6 +191,13 @@ static void eap_tls_process(struct eap_sm *sm, void *priv,
|
||||
data->state = FAILURE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (tls_connection_get_write_alerts(sm->ssl_ctx, data->ssl.conn) > 1) {
|
||||
wpa_printf(MSG_INFO, "EAP-TLS: Locally detected fatal error "
|
||||
"in TLS processing");
|
||||
data->state = FAILURE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -38,8 +38,7 @@ int eap_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tls_connection_set_verify(sm->ssl_ctx, data->conn, verify_peer,
|
||||
NULL)) {
|
||||
if (tls_connection_set_verify(sm->ssl_ctx, data->conn, verify_peer)) {
|
||||
wpa_printf(MSG_INFO, "SSL: Failed to configure verification "
|
||||
"of TLS peer certificate");
|
||||
tls_connection_deinit(sm->ssl_ctx, data->conn);
|
||||
@ -185,6 +184,13 @@ int eap_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
|
||||
wpa_printf(MSG_DEBUG, "SSL: No data to be sent out");
|
||||
free(data->tls_out);
|
||||
data->tls_out = NULL;
|
||||
|
||||
if (tls_connection_get_read_alerts(sm->ssl_ctx, data->conn)) {
|
||||
wpa_printf(MSG_DEBUG, "SSL: Remote end sent a fatal "
|
||||
"alert - abort handshake");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "eap_tls_common.h"
|
||||
#include "ms_funcs.h"
|
||||
#include "md5.h"
|
||||
#include "crypto.h"
|
||||
#include "tls.h"
|
||||
#include "eap_ttls.h"
|
||||
|
||||
@ -567,8 +568,9 @@ static void eap_ttls_process_phase2_chap(struct eap_sm *sm,
|
||||
const u8 *password,
|
||||
size_t password_len)
|
||||
{
|
||||
MD5_CTX context;
|
||||
u8 *chal, hash[MD5_MAC_LEN];
|
||||
const u8 *addr[3];
|
||||
size_t len[3];
|
||||
|
||||
if (challenge == NULL || password == NULL ||
|
||||
challenge_len != EAP_TTLS_CHAP_CHALLENGE_LEN ||
|
||||
@ -609,11 +611,13 @@ static void eap_ttls_process_phase2_chap(struct eap_sm *sm,
|
||||
free(chal);
|
||||
|
||||
/* MD5(Ident + Password + Challenge) */
|
||||
MD5Init(&context);
|
||||
MD5Update(&context, password, 1);
|
||||
MD5Update(&context, sm->user->password, sm->user->password_len);
|
||||
MD5Update(&context, challenge, challenge_len);
|
||||
MD5Final(hash, &context);
|
||||
addr[0] = password;
|
||||
len[0] = 1;
|
||||
addr[1] = sm->user->password;
|
||||
len[1] = sm->user->password_len;
|
||||
addr[2] = challenge;
|
||||
len[2] = challenge_len;
|
||||
md5_vector(3, addr, len, hash);
|
||||
|
||||
if (memcmp(hash, password + 1, EAP_TTLS_CHAP_PASSWORD_LEN) == 0) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Correct user password");
|
||||
@ -1128,6 +1132,12 @@ static void eap_ttls_process(struct eap_sm *sm, void *priv,
|
||||
data->state, __func__);
|
||||
break;
|
||||
}
|
||||
|
||||
if (tls_connection_get_write_alerts(sm->ssl_ctx, data->ssl.conn) > 1) {
|
||||
wpa_printf(MSG_INFO, "EAP-TTLS: Locally detected fatal error "
|
||||
"in TLS processing");
|
||||
eap_ttls_state(data, FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -66,6 +66,9 @@ static void sm_ ## machine ## _Step(struct eapol_state_machine *sm)
|
||||
#define SM_STEP_RUN(machine) sm_ ## machine ## _Step(sm)
|
||||
|
||||
|
||||
static void eapol_sm_step_run(struct eapol_state_machine *sm);
|
||||
static void eapol_sm_step_cb(void *eloop_ctx, void *timeout_ctx);
|
||||
|
||||
|
||||
/* Port Timers state machine - implemented as a function that will be called
|
||||
* once a second as a registered event loop timeout */
|
||||
@ -74,19 +77,34 @@ static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
struct eapol_state_machine *state = timeout_ctx;
|
||||
|
||||
if (state->aWhile > 0)
|
||||
if (state->aWhile > 0) {
|
||||
state->aWhile--;
|
||||
if (state->quietWhile > 0)
|
||||
if (state->aWhile == 0) {
|
||||
wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
|
||||
" - aWhile --> 0",
|
||||
MAC2STR(state->addr));
|
||||
}
|
||||
}
|
||||
|
||||
if (state->quietWhile > 0) {
|
||||
state->quietWhile--;
|
||||
if (state->reAuthWhen > 0)
|
||||
if (state->quietWhile == 0) {
|
||||
wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
|
||||
" - quietWhile --> 0",
|
||||
MAC2STR(state->addr));
|
||||
}
|
||||
}
|
||||
|
||||
if (state->reAuthWhen > 0) {
|
||||
state->reAuthWhen--;
|
||||
if (state->reAuthWhen == 0) {
|
||||
wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
|
||||
" - reAuthWhen --> 0",
|
||||
MAC2STR(state->addr));
|
||||
}
|
||||
}
|
||||
|
||||
if (state->hapd->conf->debug >= HOSTAPD_DEBUG_MSGDUMPS)
|
||||
printf("IEEE 802.1X: " MACSTR " Port Timers TICK "
|
||||
"(timers: %d %d %d)\n", MAC2STR(state->addr),
|
||||
state->aWhile, state->quietWhile, state->reAuthWhen);
|
||||
|
||||
eapol_sm_step(state);
|
||||
eapol_sm_step_run(state);
|
||||
|
||||
eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx, state);
|
||||
}
|
||||
@ -357,6 +375,19 @@ SM_STATE(BE_AUTH, REQUEST)
|
||||
txReq();
|
||||
sm->be_auth.eapReq = FALSE;
|
||||
sm->be_auth.backendOtherRequestsToSupplicant++;
|
||||
|
||||
/*
|
||||
* Clearing eapolEap here is not specified in IEEE Std 802.1X-2004, but
|
||||
* it looks like this would be logical thing to do there since the old
|
||||
* EAP response would not be valid anymore after the new EAP request
|
||||
* was sent out.
|
||||
*
|
||||
* A race condition has been reported, in which hostapd ended up
|
||||
* sending out EAP-Response/Identity as a response to the first
|
||||
* EAP-Request from the main EAP method. This can be avoided by
|
||||
* clearing eapolEap here.
|
||||
*/
|
||||
sm->eapolEap = FALSE;
|
||||
}
|
||||
|
||||
|
||||
@ -703,7 +734,7 @@ eapol_sm_alloc(hostapd *hapd, struct sta_info *sta)
|
||||
else
|
||||
sm->portValid = TRUE;
|
||||
|
||||
if (hapd->conf->eap_authenticator) {
|
||||
if (hapd->conf->eap_server) {
|
||||
struct eap_config eap_conf;
|
||||
memset(&eap_conf, 0, sizeof(eap_conf));
|
||||
eap_conf.ssl_ctx = hapd->ssl_ctx;
|
||||
@ -727,6 +758,7 @@ void eapol_sm_free(struct eapol_state_machine *sm)
|
||||
return;
|
||||
|
||||
eloop_cancel_timeout(eapol_port_timers_tick, sm->hapd, sm);
|
||||
eloop_cancel_timeout(eapol_sm_step_cb, sm, NULL);
|
||||
if (sm->eap)
|
||||
eap_sm_deinit(sm->eap);
|
||||
free(sm);
|
||||
@ -743,55 +775,63 @@ static int eapol_sm_sta_entry_alive(struct hostapd_data *hapd, u8 *addr)
|
||||
}
|
||||
|
||||
|
||||
void eapol_sm_step(struct eapol_state_machine *sm)
|
||||
static void eapol_sm_step_run(struct eapol_state_machine *sm)
|
||||
{
|
||||
struct hostapd_data *hapd = sm->hapd;
|
||||
u8 addr[ETH_ALEN];
|
||||
int prev_auth_pae, prev_be_auth, prev_reauth_timer, prev_auth_key_tx,
|
||||
prev_key_rx, prev_ctrl_dir;
|
||||
|
||||
/* FIX: could re-run eapol_sm_step from registered timeout (after
|
||||
* 0 sec) to make sure that other possible timeouts/events are
|
||||
* processed */
|
||||
int max_steps = 100;
|
||||
|
||||
memcpy(addr, sm->sta->addr, ETH_ALEN);
|
||||
restart:
|
||||
do {
|
||||
prev_auth_pae = sm->auth_pae.state;
|
||||
prev_be_auth = sm->be_auth.state;
|
||||
prev_reauth_timer = sm->reauth_timer.state;
|
||||
prev_auth_key_tx = sm->auth_key_tx.state;
|
||||
prev_key_rx = sm->key_rx.state;
|
||||
prev_ctrl_dir = sm->ctrl_dir.state;
|
||||
|
||||
SM_STEP_RUN(AUTH_PAE);
|
||||
if (!sm->initializing && !eapol_sm_sta_entry_alive(hapd, addr))
|
||||
break;
|
||||
/*
|
||||
* Allow EAPOL state machines to run as long as there are state
|
||||
* changes, but exit and return here through event loop if more than
|
||||
* 100 steps is needed as a precaution against infinite loops inside
|
||||
* eloop callback.
|
||||
*/
|
||||
restart:
|
||||
prev_auth_pae = sm->auth_pae.state;
|
||||
prev_be_auth = sm->be_auth.state;
|
||||
prev_reauth_timer = sm->reauth_timer.state;
|
||||
prev_auth_key_tx = sm->auth_key_tx.state;
|
||||
prev_key_rx = sm->key_rx.state;
|
||||
prev_ctrl_dir = sm->ctrl_dir.state;
|
||||
|
||||
SM_STEP_RUN(AUTH_PAE);
|
||||
if (sm->initializing || eapol_sm_sta_entry_alive(hapd, addr))
|
||||
SM_STEP_RUN(BE_AUTH);
|
||||
if (!sm->initializing && !eapol_sm_sta_entry_alive(hapd, addr))
|
||||
break;
|
||||
if (sm->initializing || eapol_sm_sta_entry_alive(hapd, addr))
|
||||
SM_STEP_RUN(REAUTH_TIMER);
|
||||
if (!sm->initializing && !eapol_sm_sta_entry_alive(hapd, addr))
|
||||
break;
|
||||
if (sm->initializing || eapol_sm_sta_entry_alive(hapd, addr))
|
||||
SM_STEP_RUN(AUTH_KEY_TX);
|
||||
if (!sm->initializing && !eapol_sm_sta_entry_alive(hapd, addr))
|
||||
break;
|
||||
if (sm->initializing || eapol_sm_sta_entry_alive(hapd, addr))
|
||||
SM_STEP_RUN(KEY_RX);
|
||||
if (!sm->initializing && !eapol_sm_sta_entry_alive(hapd, addr))
|
||||
break;
|
||||
if (sm->initializing || eapol_sm_sta_entry_alive(hapd, addr))
|
||||
SM_STEP_RUN(CTRL_DIR);
|
||||
if (!sm->initializing && !eapol_sm_sta_entry_alive(hapd, addr))
|
||||
break;
|
||||
} while (prev_auth_pae != sm->auth_pae.state ||
|
||||
prev_be_auth != sm->be_auth.state ||
|
||||
prev_reauth_timer != sm->reauth_timer.state ||
|
||||
prev_auth_key_tx != sm->auth_key_tx.state ||
|
||||
prev_key_rx != sm->key_rx.state ||
|
||||
prev_ctrl_dir != sm->ctrl_dir.state);
|
||||
|
||||
if (prev_auth_pae != sm->auth_pae.state ||
|
||||
prev_be_auth != sm->be_auth.state ||
|
||||
prev_reauth_timer != sm->reauth_timer.state ||
|
||||
prev_auth_key_tx != sm->auth_key_tx.state ||
|
||||
prev_key_rx != sm->key_rx.state ||
|
||||
prev_ctrl_dir != sm->ctrl_dir.state) {
|
||||
if (--max_steps > 0)
|
||||
goto restart;
|
||||
/* Re-run from eloop timeout */
|
||||
eapol_sm_step(sm);
|
||||
return;
|
||||
}
|
||||
|
||||
if (eapol_sm_sta_entry_alive(hapd, addr) && sm->eap) {
|
||||
if (eap_sm_step(sm->eap))
|
||||
goto restart;
|
||||
if (eap_sm_step(sm->eap)) {
|
||||
if (--max_steps > 0)
|
||||
goto restart;
|
||||
/* Re-run from eloop timeout */
|
||||
eapol_sm_step(sm);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (eapol_sm_sta_entry_alive(hapd, addr))
|
||||
@ -799,15 +839,34 @@ void eapol_sm_step(struct eapol_state_machine *sm)
|
||||
}
|
||||
|
||||
|
||||
static void eapol_sm_step_cb(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
struct eapol_state_machine *sm = eloop_ctx;
|
||||
eapol_sm_step_run(sm);
|
||||
}
|
||||
|
||||
|
||||
void eapol_sm_step(struct eapol_state_machine *sm)
|
||||
{
|
||||
/*
|
||||
* Run eapol_sm_step_run from a registered timeout to make sure that
|
||||
* other possible timeouts/events are processed and to avoid long
|
||||
* function call chains.
|
||||
*/
|
||||
|
||||
eloop_register_timeout(0, 0, eapol_sm_step_cb, sm, NULL);
|
||||
}
|
||||
|
||||
|
||||
void eapol_sm_initialize(struct eapol_state_machine *sm)
|
||||
{
|
||||
sm->initializing = TRUE;
|
||||
/* Initialize the state machines by asserting initialize and then
|
||||
* deasserting it after one step */
|
||||
sm->initialize = TRUE;
|
||||
eapol_sm_step(sm);
|
||||
eapol_sm_step_run(sm);
|
||||
sm->initialize = FALSE;
|
||||
eapol_sm_step(sm);
|
||||
eapol_sm_step_run(sm);
|
||||
sm->initializing = FALSE;
|
||||
|
||||
/* Start one second tick for port timers state machine */
|
||||
@ -1181,6 +1240,14 @@ static int eapol_sm_get_eap_user(void *ctx, const u8 *identity,
|
||||
}
|
||||
|
||||
|
||||
static const char * eapol_sm_get_eap_req_id_text(void *ctx, size_t *len)
|
||||
{
|
||||
struct eapol_state_machine *sm = ctx;
|
||||
*len = sm->hapd->conf->eap_req_id_text_len;
|
||||
return sm->hapd->conf->eap_req_id_text;
|
||||
}
|
||||
|
||||
|
||||
static struct eapol_callbacks eapol_cb =
|
||||
{
|
||||
.get_bool = eapol_sm_get_bool,
|
||||
@ -1188,4 +1255,5 @@ static struct eapol_callbacks eapol_cb =
|
||||
.set_eapReqData = eapol_sm_set_eapReqData,
|
||||
.set_eapKeyData = eapol_sm_set_eapKeyData,
|
||||
.get_eap_user = eapol_sm_get_eap_user,
|
||||
.get_eap_req_id_text = eapol_sm_get_eap_req_id_text,
|
||||
};
|
||||
|
@ -110,6 +110,16 @@ struct eapol_ctrl_dir {
|
||||
|
||||
struct eap_sm;
|
||||
|
||||
struct radius_attr_data {
|
||||
u8 *data;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
struct radius_class_data {
|
||||
struct radius_attr_data *attr;
|
||||
size_t count;
|
||||
};
|
||||
|
||||
struct eapol_state_machine {
|
||||
/* timers */
|
||||
int aWhile;
|
||||
@ -175,8 +185,7 @@ struct eapol_state_machine {
|
||||
size_t last_eap_radius_len;
|
||||
u8 *identity;
|
||||
size_t identity_len;
|
||||
u8 *radius_class;
|
||||
size_t radius_class_len;
|
||||
struct radius_class_data radius_class;
|
||||
|
||||
/* Keys for encrypting and signing EAPOL-Key frames */
|
||||
u8 *eapol_key_sign;
|
||||
|
@ -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 */
|
||||
|
@ -423,6 +423,7 @@ enum {
|
||||
PRISM2_PARAM_PRIVACY_INVOKED = 37,
|
||||
PRISM2_PARAM_TKIP_COUNTERMEASURES = 38,
|
||||
PRISM2_PARAM_DROP_UNENCRYPTED = 39,
|
||||
PRISM2_PARAM_SCAN_CHANNEL_MASK = 40,
|
||||
};
|
||||
|
||||
enum { HOSTAP_ANTSEL_DO_NOT_TOUCH = 0, HOSTAP_ANTSEL_DIVERSITY = 1,
|
||||
|
56
contrib/hostapd/hostapd.8
Normal file
56
contrib/hostapd/hostapd.8
Normal file
@ -0,0 +1,56 @@
|
||||
.TH HOSTAPD 8 "April 7, 2005" hostapd hostapd
|
||||
.SH NAME
|
||||
hostapd \- IEEE 802.11 AP, IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator
|
||||
.SH SYNOPSIS
|
||||
.B hostapd
|
||||
[-hdBKt] <configuration file(s)>
|
||||
.SH DESCRIPTION
|
||||
This manual page documents briefly the
|
||||
.B hostapd
|
||||
daemon.
|
||||
.PP
|
||||
.B hostapd
|
||||
is a user space daemon for access point and authentication servers.
|
||||
It implements IEEE 802.11 access point management, IEEE 802.1X/WPA/WPA2/EAP Authenticators and RADIUS authentication server.
|
||||
The current version supports Linux (Host AP, madwifi, Prism54 drivers) and FreeBSD (net80211).
|
||||
|
||||
.B hostapd
|
||||
is designed to be a "daemon" program that runs in the background and acts as the backend component controlling authentication.
|
||||
.B hostapd
|
||||
supports separate frontend programs and an example text-based frontend,
|
||||
.BR hostapd_cli ,
|
||||
is included with
|
||||
.BR hostapd .
|
||||
.SH OPTIONS
|
||||
A summary of options is included below.
|
||||
For a complete description, run
|
||||
.BR hostapd
|
||||
from the command line.
|
||||
.TP
|
||||
.B \-h
|
||||
Show usage.
|
||||
.TP
|
||||
.B \-d
|
||||
Show more debug messages.
|
||||
.TP
|
||||
.B \-dd
|
||||
Show even more debug messages.
|
||||
.TP
|
||||
.B \-B
|
||||
Run daemon in the background.
|
||||
.TP
|
||||
.B \-K
|
||||
Include key data in debug messages.
|
||||
.TP
|
||||
.B \-t
|
||||
Include timestamps in some debug messages.
|
||||
.TP
|
||||
.B \-v
|
||||
Show hostapd version.
|
||||
.SH SEE ALSO
|
||||
.BR hostapd_cli (1).
|
||||
.SH AUTHOR
|
||||
hostapd was written by Jouni Malinen <jkmaline@cc.hut.fi>.
|
||||
.PP
|
||||
This manual page was written by Faidon Liambotis <faidon@cube.gr>,
|
||||
for the Debian project (but may be used by others).
|
@ -24,6 +24,7 @@
|
||||
#include <stdarg.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "eloop.h"
|
||||
#include "hostapd.h"
|
||||
@ -43,6 +44,7 @@
|
||||
#include "tls.h"
|
||||
#include "eap_sim_db.h"
|
||||
#include "version.h"
|
||||
#include "hostap_common.h"
|
||||
|
||||
|
||||
struct hapd_interfaces {
|
||||
@ -58,8 +60,8 @@ extern int wpa_debug_show_keys;
|
||||
extern int wpa_debug_timestamp;
|
||||
|
||||
|
||||
void hostapd_logger(hostapd *hapd, u8 *addr, unsigned int module, int level,
|
||||
char *fmt, ...)
|
||||
void hostapd_logger(struct hostapd_data *hapd, const u8 *addr,
|
||||
unsigned int module, int level, const char *fmt, ...)
|
||||
{
|
||||
char *format, *module_str;
|
||||
int maxlen;
|
||||
@ -72,8 +74,6 @@ void hostapd_logger(hostapd *hapd, u8 *addr, unsigned int module, int level,
|
||||
if (!format)
|
||||
return;
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
||||
if (hapd && hapd->conf) {
|
||||
conf_syslog_level = hapd->conf->logger_syslog_level;
|
||||
conf_stdout_level = hapd->conf->logger_stdout_level;
|
||||
@ -125,7 +125,10 @@ void hostapd_logger(hostapd *hapd, u8 *addr, unsigned int module, int level,
|
||||
module_str, module_str ? ": " : "", fmt);
|
||||
|
||||
if ((conf_stdout & module) && level >= conf_stdout_level) {
|
||||
wpa_debug_print_timestamp();
|
||||
va_start(ap, fmt);
|
||||
vprintf(format, ap);
|
||||
va_end(ap);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
@ -149,12 +152,34 @@ void hostapd_logger(hostapd *hapd, u8 *addr, unsigned int module, int level,
|
||||
priority = LOG_INFO;
|
||||
break;
|
||||
}
|
||||
va_start(ap, fmt);
|
||||
vsyslog(priority, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
free(format);
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@ -175,20 +200,30 @@ static void hostapd_deauth_all_stas(hostapd *hapd)
|
||||
|
||||
|
||||
/* This function will be called whenever a station associates with the AP */
|
||||
void hostapd_new_assoc_sta(hostapd *hapd, struct sta_info *sta)
|
||||
void hostapd_new_assoc_sta(hostapd *hapd, struct sta_info *sta, int reassoc)
|
||||
{
|
||||
if (hapd->tkip_countermeasures) {
|
||||
hostapd_sta_deauth(hapd, sta->addr,
|
||||
WLAN_REASON_MICHAEL_MIC_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
/* IEEE 802.11F (IAPP) */
|
||||
if (hapd->conf->ieee802_11f)
|
||||
iapp_new_station(hapd->iapp, sta);
|
||||
|
||||
/* Start accounting here, if IEEE 802.1X is not used. IEEE 802.1X code
|
||||
* will start accounting after the station has been authorized. */
|
||||
if (!hapd->conf->ieee802_1x)
|
||||
/* Start accounting here, if IEEE 802.1X and WPA are not used.
|
||||
* IEEE 802.1X/WPA code will start accounting after the station has
|
||||
* been authorized. */
|
||||
if (!hapd->conf->ieee802_1x && !hapd->conf->wpa)
|
||||
accounting_sta_start(hapd, sta);
|
||||
|
||||
/* Start IEEE 802.1x authentication process for new stations */
|
||||
/* Start IEEE 802.1X authentication process for new stations */
|
||||
ieee802_1x_new_station(hapd, sta);
|
||||
wpa_new_station(hapd, sta);
|
||||
if (reassoc)
|
||||
wpa_sm_event(hapd, sta, WPA_REAUTH);
|
||||
else
|
||||
wpa_new_station(hapd, sta);
|
||||
}
|
||||
|
||||
|
||||
@ -438,7 +473,9 @@ static int hostapd_setup_interface(struct hostapd_data *hapd)
|
||||
return -1;
|
||||
}
|
||||
|
||||
hapd->radius = radius_client_init(hapd);
|
||||
if (HOSTAPD_DEBUG_COND(HOSTAPD_DEBUG_MSGDUMPS))
|
||||
conf->radius->msg_dumps = 1;
|
||||
hapd->radius = radius_client_init(hapd, conf->radius);
|
||||
if (hapd->radius == NULL) {
|
||||
printf("RADIUS client initialization failed.\n");
|
||||
return -1;
|
||||
@ -451,6 +488,7 @@ static int hostapd_setup_interface(struct hostapd_data *hapd)
|
||||
srv.hostapd_conf = conf;
|
||||
srv.eap_sim_db_priv = hapd->eap_sim_db_priv;
|
||||
srv.ssl_ctx = hapd->ssl_ctx;
|
||||
srv.ipv6 = conf->radius_server_ipv6;
|
||||
hapd->radius_srv = radius_server_init(&srv);
|
||||
if (hapd->radius_srv == NULL) {
|
||||
printf("RADIUS server initialization failed.\n");
|
||||
@ -580,8 +618,8 @@ static void show_version(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"hostapd v" VERSION_STR "\n"
|
||||
"Host AP user space daemon for management functionality of "
|
||||
"Host AP kernel driver\n"
|
||||
"User space daemon for IEEE 802.11 AP management,\n"
|
||||
"IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
|
||||
"Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi> "
|
||||
"and contributors\n");
|
||||
}
|
||||
@ -592,7 +630,7 @@ static void usage(void)
|
||||
show_version();
|
||||
fprintf(stderr,
|
||||
"\n"
|
||||
"usage: hostapd [-hdB] <configuration file(s)>\n"
|
||||
"usage: hostapd [-hdBKt] <configuration file(s)>\n"
|
||||
"\n"
|
||||
"options:\n"
|
||||
" -h show this usage\n"
|
||||
@ -634,9 +672,9 @@ static hostapd * hostapd_init(const char *config_file)
|
||||
}
|
||||
|
||||
#ifdef EAP_TLS_FUNCS
|
||||
if (hapd->conf->eap_authenticator &&
|
||||
if (hapd->conf->eap_server &&
|
||||
(hapd->conf->ca_cert || hapd->conf->server_cert)) {
|
||||
hapd->ssl_ctx = tls_init();
|
||||
hapd->ssl_ctx = tls_init(NULL);
|
||||
if (hapd->ssl_ctx == NULL) {
|
||||
printf("Failed to initialize TLS\n");
|
||||
goto fail;
|
||||
@ -657,6 +695,12 @@ static hostapd * hostapd_init(const char *config_file)
|
||||
hapd->conf->private_key_passwd)) {
|
||||
printf("Failed to load private key (%s)\n",
|
||||
hapd->conf->private_key);
|
||||
goto fail;
|
||||
}
|
||||
if (tls_global_set_verify(hapd->ssl_ctx,
|
||||
hapd->conf->check_crl)) {
|
||||
printf("Failed to enable check_crl\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
#endif /* EAP_TLS_FUNCS */
|
||||
|
@ -2,9 +2,14 @@
|
||||
# Empty lines and lines starting with # are ignored
|
||||
|
||||
# AP netdevice name (without 'ap' prefix, i.e., wlan0 uses wlan0ap for
|
||||
# management frames)
|
||||
# management frames); ath0 for madwifi
|
||||
interface=wlan0
|
||||
|
||||
# In case of madwifi driver, an additional configuration parameter, bridge,
|
||||
# must be used to notify hostapd if the interface is included in a bridge. This
|
||||
# parameter is not used with Host AP driver.
|
||||
#bridge=br0
|
||||
|
||||
# Driver interface type (hostap/wired/madwifi/prism54; default: hostap)
|
||||
# driver=hostap
|
||||
|
||||
@ -40,7 +45,7 @@ debug=0
|
||||
# Dump file for state information (on SIGUSR1)
|
||||
dump_file=/tmp/hostapd.dump
|
||||
|
||||
# Interface for separate control program. If this is specified, wpa_supplicant
|
||||
# Interface for separate control program. If this is specified, hostapd
|
||||
# will create this directory and a UNIX domain socket for listening to requests
|
||||
# from external programs (CLI/GUI, etc.) for status information and
|
||||
# configuration. The socket file will be named based on the interface name, so
|
||||
@ -52,11 +57,11 @@ ctrl_interface=/var/run/hostapd
|
||||
|
||||
# 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
|
||||
# possible to run hostapd 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
|
||||
# cases. By default, hostapd is configured to use gid 0 (root). If you
|
||||
# want to allow non-root users to use the contron 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.
|
||||
@ -96,42 +101,17 @@ auth_algs=3
|
||||
#assoc_ap_addr=00:12:34:56:78:9a
|
||||
|
||||
|
||||
##### IEEE 802.1X (and IEEE 802.1aa/D4) related configuration #################
|
||||
##### IEEE 802.1X-2004 related configuration ##################################
|
||||
|
||||
# Require IEEE 802.1X authorization
|
||||
#ieee8021x=1
|
||||
|
||||
# Use integrated EAP authenticator instead of external RADIUS authentication
|
||||
# server
|
||||
eap_authenticator=0
|
||||
|
||||
# Path for EAP authenticator user database
|
||||
#eap_user_file=/etc/hostapd.eap_user
|
||||
|
||||
# CA certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS
|
||||
#ca_cert=/etc/hostapd.ca.pem
|
||||
|
||||
# Server certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS
|
||||
#server_cert=/etc/hostapd.server.pem
|
||||
|
||||
# Private key matching with the server certificate for EAP-TLS/PEAP/TTLS
|
||||
# This may point to the same file as server_cert if both certificate and key
|
||||
# are included in a single file. PKCS#12 (PFX) file (.p12/.pfx) can also be
|
||||
# used by commenting out server_cert and specifying the PFX file as the
|
||||
# private_key.
|
||||
#private_key=/etc/hostapd.server.prv
|
||||
|
||||
# Passphrase for private key
|
||||
#private_key_passwd=secret passphrase
|
||||
|
||||
# Configuration data for EAP-SIM database/authentication gateway interface.
|
||||
# This is a text string in implementation specific format. The example
|
||||
# implementation in eap_sim_db.c uses this as the file name for the GSM
|
||||
# authentication triplets.
|
||||
#eap_sim_db=/etc/hostapd.sim_db
|
||||
|
||||
# Optional displayable message sent with EAP Request-Identity
|
||||
eap_message=hello
|
||||
# Optional displayable message sent with EAP Request-Identity. The first \0
|
||||
# in this string will be converted to ASCII-0 (nul). This can be used to
|
||||
# separate network info (comma separated list of attribute=value pairs); see,
|
||||
# e.g., draft-adrangi-eap-network-discovery-07.txt.
|
||||
#eap_message=hello
|
||||
#eap_message=hello\0networkid=netw,nasid=foo,portid=0,NAIRealms=example.com
|
||||
|
||||
# WEP rekeying (disabled if key lengths are not set or are set to 0)
|
||||
# Key lengths for default/broadcast and individual/unicast keys:
|
||||
@ -150,13 +130,68 @@ eapol_key_index_workaround=0
|
||||
# reauthentication).
|
||||
#eap_reauth_period=3600
|
||||
|
||||
# Use PAE group address (01:80:c2:00:00:03) instead of individual target
|
||||
# address when sending EAPOL frames with driver=wired. This is the most common
|
||||
# mechanism used in wired authentication, but it also requires that the port
|
||||
# is only used by one station.
|
||||
#use_pae_group_addr=1
|
||||
|
||||
##### Integrated EAP server ###################################################
|
||||
|
||||
# Optionally, hostapd can be configured to use an integrated EAP server
|
||||
# to process EAP authentication locally without need for an external RADIUS
|
||||
# server. This functionality can be used both as a local authentication server
|
||||
# for IEEE 802.1X/EAPOL and as a RADIUS server for other devices.
|
||||
|
||||
# Use integrated EAP server instead of external RADIUS authentication
|
||||
# server. This is also needed if hostapd is configured to act as a RADIUS
|
||||
# authentication server.
|
||||
eap_server=0
|
||||
|
||||
# Path for EAP server user database
|
||||
#eap_user_file=/etc/hostapd.eap_user
|
||||
|
||||
# CA certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS
|
||||
#ca_cert=/etc/hostapd.ca.pem
|
||||
|
||||
# Server certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS
|
||||
#server_cert=/etc/hostapd.server.pem
|
||||
|
||||
# Private key matching with the server certificate for EAP-TLS/PEAP/TTLS
|
||||
# This may point to the same file as server_cert if both certificate and key
|
||||
# are included in a single file. PKCS#12 (PFX) file (.p12/.pfx) can also be
|
||||
# used by commenting out server_cert and specifying the PFX file as the
|
||||
# private_key.
|
||||
#private_key=/etc/hostapd.server.prv
|
||||
|
||||
# Passphrase for private key
|
||||
#private_key_passwd=secret passphrase
|
||||
|
||||
# Enable CRL verification.
|
||||
# Note: hostapd does not yet support CRL downloading based on CDP. Thus, a
|
||||
# valid CRL signed by the CA is required to be included in the ca_cert file.
|
||||
# This can be done by using PEM format for CA certificate and CRL and
|
||||
# concatenating these into one file. Whenever CRL changes, hostapd needs to be
|
||||
# restarted to take the new CRL into use.
|
||||
# 0 = do not verify CRLs (default)
|
||||
# 1 = check the CRL of the user certificate
|
||||
# 2 = check all CRLs in the certificate path
|
||||
#check_crl=1
|
||||
|
||||
# Configuration data for EAP-SIM database/authentication gateway interface.
|
||||
# This is a text string in implementation specific format. The example
|
||||
# implementation in eap_sim_db.c uses this as the file name for the GSM
|
||||
# authentication triplets.
|
||||
#eap_sim_db=/etc/hostapd.sim_db
|
||||
|
||||
|
||||
##### IEEE 802.11f - Inter-Access Point Protocol (IAPP) #######################
|
||||
|
||||
# Interface to be used for IAPP broadcast packets
|
||||
#iapp_interface=eth0
|
||||
|
||||
|
||||
##### RADIUS configuration ####################################################
|
||||
##### RADIUS client configuration #############################################
|
||||
# for IEEE 802.1X with external Authentication Server, IEEE 802.11
|
||||
# authentication with external ACL for MAC addresses, and accounting
|
||||
|
||||
@ -208,6 +243,8 @@ own_ip_addr=127.0.0.1
|
||||
#radius_acct_interim_interval=600
|
||||
|
||||
|
||||
##### RADIUS authentication server configuration ##############################
|
||||
|
||||
# hostapd can be used as a RADIUS authentication server for other hosts. This
|
||||
# requires that the integrated EAP authenticator is also enabled and both
|
||||
# authentication services are sharing the same configuration.
|
||||
@ -219,6 +256,9 @@ own_ip_addr=127.0.0.1
|
||||
# The UDP port number for the RADIUS authentication server
|
||||
#radius_server_auth_port=1812
|
||||
|
||||
# Use IPv6 with RADIUS server (IPv4 will also be supported using IPv6 API)
|
||||
#radius_server_ipv6=1
|
||||
|
||||
|
||||
##### WPA/IEEE 802.11i configuration ##########################################
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
# phase 1 and another with the same username for phase 2.
|
||||
#
|
||||
# EAP-TLS, EAP-PEAP, EAP-TTLS, and EAP-SIM do not use password option.
|
||||
# EAP-MD5, EAP-MSCHAPV2, and EAP-GTC require a password.
|
||||
# EAP-MD5, EAP-MSCHAPV2, EAP-GTC, EAP-PAX, and EAP-PSK require a password.
|
||||
# EAP-PEAP and EAP-TTLS require Phase 2 configuration.
|
||||
#
|
||||
# * can be used as a wildcard to match any user identity. The main purposes for
|
||||
@ -33,6 +33,10 @@
|
||||
"example user" TLS
|
||||
"DOMAIN\user" MSCHAPV2 "password"
|
||||
"gtc user" GTC "password"
|
||||
"pax user" PAX "unknown"
|
||||
"pax.user@example.com" PAX 0123456789abcdef0123456789abcdef
|
||||
"psk user" PSK "unknown"
|
||||
"psk.user@example.com" PSK 0123456789abcdef0123456789abcdef
|
||||
"ttls" TTLS
|
||||
"not anonymous" PEAP
|
||||
* PEAP,TTLS,TLS,SIM
|
||||
|
@ -13,8 +13,19 @@
|
||||
#ifndef ETH_P_ALL
|
||||
#define ETH_P_ALL 0x0003
|
||||
#endif
|
||||
#ifndef ETH_P_PAE
|
||||
#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
|
||||
#endif /* ETH_P_PAE */
|
||||
|
||||
#ifndef BIT
|
||||
#define BIT(x) (1 << (x))
|
||||
#endif
|
||||
|
||||
#ifndef MAC2STR
|
||||
#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
|
||||
#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
|
||||
#endif
|
||||
|
||||
#include "hostap_common.h"
|
||||
#include "config.h"
|
||||
|
||||
struct ieee8023_hdr {
|
||||
@ -118,9 +129,10 @@ struct hostapd_data {
|
||||
struct radius_server_data *radius_srv;
|
||||
};
|
||||
|
||||
void hostapd_new_assoc_sta(hostapd *hapd, struct sta_info *sta);
|
||||
void hostapd_logger(hostapd *hapd, u8 *addr, unsigned int module, int level,
|
||||
char *fmt, ...) __attribute__ ((format (printf, 5, 6)));
|
||||
void hostapd_new_assoc_sta(hostapd *hapd, struct sta_info *sta, int reassoc);
|
||||
void hostapd_logger(struct hostapd_data *hapd, const u8 *addr,
|
||||
unsigned int module, int level, const char *fmt,
|
||||
...) __attribute__ ((format (printf, 5, 6)));
|
||||
|
||||
|
||||
#define HOSTAPD_DEBUG(level, args...) \
|
||||
@ -131,4 +143,7 @@ do { \
|
||||
|
||||
#define HOSTAPD_DEBUG_COND(level) (hapd->conf->debug >= (level))
|
||||
|
||||
const char * hostapd_ip_txt(const struct hostapd_ip_addr *addr, char *buf,
|
||||
size_t buflen);
|
||||
|
||||
#endif /* HOSTAPD_H */
|
||||
|
83
contrib/hostapd/hostapd_cli.1
Normal file
83
contrib/hostapd/hostapd_cli.1
Normal file
@ -0,0 +1,83 @@
|
||||
.TH HOSTAPD_CLI 1 "April 7, 2005" hostapd_cli "hostapd command-line interface"
|
||||
.SH NAME
|
||||
hostapd_cli \- hostapd command-line interface
|
||||
.SH SYNOPSIS
|
||||
.B hostapd_cli
|
||||
[-p<path>] [-i<ifname>] [-hv] [command..]
|
||||
.SH DESCRIPTION
|
||||
This manual page documents briefly the
|
||||
.B hostapd_cli
|
||||
utility.
|
||||
.PP
|
||||
.B hostapd_cli
|
||||
is a command-line interface for the
|
||||
.B hostapd
|
||||
daemon.
|
||||
|
||||
.B hostapd
|
||||
is a user space daemon for access point and authentication servers.
|
||||
It implements IEEE 802.11 access point management, IEEE 802.1X/WPA/WPA2/EAP Authenticators and RADIUS authentication server.
|
||||
For more information about
|
||||
.B hostapd
|
||||
refer to the
|
||||
.BR hostapd (8)
|
||||
man page.
|
||||
.SH OPTIONS
|
||||
A summary of options is included below.
|
||||
For a complete description, run
|
||||
.BR hostapd_cli
|
||||
from the command line.
|
||||
.TP
|
||||
.B \-p<path>
|
||||
Path to find control sockets.
|
||||
|
||||
Default: /var/run/hostapd
|
||||
.TP
|
||||
.B \-i<ifname>
|
||||
Interface to listen on.
|
||||
|
||||
Default: first interface found in socket path.
|
||||
.TP
|
||||
.B \-h
|
||||
Show usage.
|
||||
.TP
|
||||
.B \-v
|
||||
Show hostapd_cli version.
|
||||
.SH COMMANDS
|
||||
A summary of commands is included below.
|
||||
For a complete description, run
|
||||
.BR hostapd_cli
|
||||
from the command line.
|
||||
.TP
|
||||
.B mib
|
||||
Get MIB variables (dot1x, dot11, radius).
|
||||
.TP
|
||||
.B sta <addr>
|
||||
Get MIB variables for one station.
|
||||
.TP
|
||||
.B all_sta
|
||||
Get MIB variables for all stations.
|
||||
.TP
|
||||
.B help
|
||||
Get usage help.
|
||||
.TP
|
||||
.B interface [ifname]
|
||||
Show interfaces/select interface.
|
||||
.TP
|
||||
.B level <debug level>
|
||||
Change debug level.
|
||||
.TP
|
||||
.B license
|
||||
Show full
|
||||
.B hostapd_cli
|
||||
license.
|
||||
.TP
|
||||
.B quit
|
||||
Exit hostapd_cli.
|
||||
.SH SEE ALSO
|
||||
.BR hostapd (8).
|
||||
.SH AUTHOR
|
||||
hostapd_cli was written by Jouni Malinen <jkmaline@cc.hut.fi>.
|
||||
.PP
|
||||
This manual page was written by Faidon Liambotis <faidon@cube.gr>,
|
||||
for the Debian project (but may be used by others).
|
@ -19,7 +19,7 @@
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "hostapd_ctrl.h"
|
||||
#include "wpa_ctrl.h"
|
||||
#include "version.h"
|
||||
|
||||
|
||||
@ -81,17 +81,17 @@ static const char *hostapd_cli_full_license =
|
||||
"\n";
|
||||
|
||||
static const char *commands_help =
|
||||
"commands:\n"
|
||||
" mib = get MIB variables (dot1x, dot11, radius)\n"
|
||||
" sta <addr> = get MIB vatiables for one station\n"
|
||||
" all_sta = get MIB variables for all stations\n"
|
||||
" help = show this usage help\n"
|
||||
" interface [ifname] = show interfaces/select interface\n"
|
||||
" level <debug level> = change debug level\n"
|
||||
" license = show full hostapd_cli license\n"
|
||||
" quit = exit hostapd_cli\n";
|
||||
"Commands:\n"
|
||||
" mib get MIB variables (dot1x, dot11, radius)\n"
|
||||
" sta <addr> get MIB vatiables for one station\n"
|
||||
" all_sta get MIB variables for all stations\n"
|
||||
" help show this usage help\n"
|
||||
" interface [ifname] show interfaces/select interface\n"
|
||||
" level <debug level> change debug level\n"
|
||||
" license show full hostapd_cli license\n"
|
||||
" quit exit hostapd_cli\n";
|
||||
|
||||
static struct hostapd_ctrl *ctrl_conn;
|
||||
static struct wpa_ctrl *ctrl_conn;
|
||||
static int hostapd_cli_quit = 0;
|
||||
static int hostapd_cli_attached = 0;
|
||||
static const char *ctrl_iface_dir = "/var/run/hostapd";
|
||||
@ -100,18 +100,26 @@ static char *ctrl_ifname = NULL;
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf("hostapd_cli [-p<path to ctrl sockets>] [-i<ifname>] [-hv] "
|
||||
"[command..]\n"
|
||||
" -h = help (show this usage text)\n"
|
||||
" -v = shown version information\n"
|
||||
" default path: /var/run/hostapd\n"
|
||||
" default interface: first interface found in socket path\n"
|
||||
"%s",
|
||||
commands_help);
|
||||
fprintf(stderr, "%s\n", hostapd_cli_version);
|
||||
fprintf(stderr,
|
||||
"\n"
|
||||
"usage: hostapd_cli [-p<path>] [-i<ifname>] [-hv] "
|
||||
"[command..]\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -h help (show this usage text)\n"
|
||||
" -v shown version information\n"
|
||||
" -p<path> path to find control sockets (default: "
|
||||
"/var/run/hostapd)\n"
|
||||
" -i<ifname> Interface to listen on (default: first "
|
||||
"interface found in the\n"
|
||||
" socket path)\n\n"
|
||||
"%s",
|
||||
commands_help);
|
||||
}
|
||||
|
||||
|
||||
static struct hostapd_ctrl * hostapd_cli_open_connection(const char *ifname)
|
||||
static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
|
||||
{
|
||||
char *cfile;
|
||||
int flen;
|
||||
@ -125,7 +133,7 @@ static struct hostapd_ctrl * hostapd_cli_open_connection(const char *ifname)
|
||||
return NULL;
|
||||
snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
|
||||
|
||||
ctrl_conn = hostapd_ctrl_open(cfile);
|
||||
ctrl_conn = wpa_ctrl_open(cfile);
|
||||
free(cfile);
|
||||
return ctrl_conn;
|
||||
}
|
||||
@ -137,10 +145,10 @@ static void hostapd_cli_close_connection(void)
|
||||
return;
|
||||
|
||||
if (hostapd_cli_attached) {
|
||||
hostapd_ctrl_detach(ctrl_conn);
|
||||
wpa_ctrl_detach(ctrl_conn);
|
||||
hostapd_cli_attached = 0;
|
||||
}
|
||||
hostapd_ctrl_close(ctrl_conn);
|
||||
wpa_ctrl_close(ctrl_conn);
|
||||
ctrl_conn = NULL;
|
||||
}
|
||||
|
||||
@ -151,8 +159,7 @@ static void hostapd_cli_msg_cb(char *msg, size_t len)
|
||||
}
|
||||
|
||||
|
||||
static int _hostapd_ctrl_command(struct hostapd_ctrl *ctrl, char *cmd,
|
||||
int print)
|
||||
static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
|
||||
{
|
||||
char buf[4096];
|
||||
size_t len;
|
||||
@ -163,7 +170,7 @@ static int _hostapd_ctrl_command(struct hostapd_ctrl *ctrl, char *cmd,
|
||||
return -1;
|
||||
}
|
||||
len = sizeof(buf) - 1;
|
||||
ret = hostapd_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
|
||||
ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
|
||||
hostapd_cli_msg_cb);
|
||||
if (ret == -2) {
|
||||
printf("'%s' command timed out.\n", cmd);
|
||||
@ -180,28 +187,25 @@ static int _hostapd_ctrl_command(struct hostapd_ctrl *ctrl, char *cmd,
|
||||
}
|
||||
|
||||
|
||||
static inline int hostapd_ctrl_command(struct hostapd_ctrl *ctrl, char *cmd)
|
||||
static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
|
||||
{
|
||||
return _hostapd_ctrl_command(ctrl, cmd, 1);
|
||||
return _wpa_ctrl_command(ctrl, cmd, 1);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_ping(struct hostapd_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
{
|
||||
return hostapd_ctrl_command(ctrl, "PING");
|
||||
return wpa_ctrl_command(ctrl, "PING");
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_mib(struct hostapd_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
{
|
||||
return hostapd_ctrl_command(ctrl, "MIB");
|
||||
return wpa_ctrl_command(ctrl, "MIB");
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_sta(struct hostapd_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
{
|
||||
char buf[64];
|
||||
if (argc != 1) {
|
||||
@ -210,12 +214,12 @@ static int hostapd_cli_cmd_sta(struct hostapd_ctrl *ctrl, int argc,
|
||||
return -1;
|
||||
}
|
||||
snprintf(buf, sizeof(buf), "STA %s", argv[0]);
|
||||
return hostapd_ctrl_command(ctrl, buf);
|
||||
return wpa_ctrl_command(ctrl, buf);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_ctrl_command_sta(struct hostapd_ctrl *ctrl, char *cmd,
|
||||
char *addr, size_t addr_len)
|
||||
static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
|
||||
char *addr, size_t addr_len)
|
||||
{
|
||||
char buf[4096], *pos;
|
||||
size_t len;
|
||||
@ -226,7 +230,7 @@ static int hostapd_ctrl_command_sta(struct hostapd_ctrl *ctrl, char *cmd,
|
||||
return -1;
|
||||
}
|
||||
len = sizeof(buf) - 1;
|
||||
ret = hostapd_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
|
||||
ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
|
||||
hostapd_cli_msg_cb);
|
||||
if (ret == -2) {
|
||||
printf("'%s' command timed out.\n", cmd);
|
||||
@ -250,30 +254,29 @@ static int hostapd_ctrl_command_sta(struct hostapd_ctrl *ctrl, char *cmd,
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_all_sta(struct hostapd_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
char addr[32], cmd[64];
|
||||
|
||||
if (hostapd_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
|
||||
if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
|
||||
return 0;
|
||||
do {
|
||||
snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
|
||||
} while (hostapd_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
|
||||
} while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_help(struct hostapd_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
{
|
||||
printf("%s", commands_help);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_license(struct hostapd_ctrl *ctrl, int argc,
|
||||
static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
|
||||
@ -281,16 +284,14 @@ static int hostapd_cli_cmd_license(struct hostapd_ctrl *ctrl, int argc,
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_quit(struct hostapd_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
{
|
||||
hostapd_cli_quit = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_level(struct hostapd_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
{
|
||||
char cmd[256];
|
||||
if (argc != 1) {
|
||||
@ -299,11 +300,11 @@ static int hostapd_cli_cmd_level(struct hostapd_ctrl *ctrl, int argc,
|
||||
return 0;
|
||||
}
|
||||
snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
|
||||
return hostapd_ctrl_command(ctrl, cmd);
|
||||
return wpa_ctrl_command(ctrl, cmd);
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_cli_list_interfaces(struct hostapd_ctrl *ctrl)
|
||||
static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
|
||||
{
|
||||
struct dirent *dent;
|
||||
DIR *dir;
|
||||
@ -326,7 +327,7 @@ static void hostapd_cli_list_interfaces(struct hostapd_ctrl *ctrl)
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_interface(struct hostapd_ctrl *ctrl, int argc,
|
||||
static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
if (argc < 1) {
|
||||
@ -340,7 +341,7 @@ static int hostapd_cli_cmd_interface(struct hostapd_ctrl *ctrl, int argc,
|
||||
|
||||
if (hostapd_cli_open_connection(ctrl_ifname)) {
|
||||
printf("Connected to interface '%s.\n", ctrl_ifname);
|
||||
if (hostapd_ctrl_attach(ctrl_conn) == 0) {
|
||||
if (wpa_ctrl_attach(ctrl_conn) == 0) {
|
||||
hostapd_cli_attached = 1;
|
||||
} else {
|
||||
printf("Warning: Failed to attach to "
|
||||
@ -356,7 +357,7 @@ static int hostapd_cli_cmd_interface(struct hostapd_ctrl *ctrl, int argc,
|
||||
|
||||
struct hostapd_cli_cmd {
|
||||
const char *cmd;
|
||||
int (*handler)(struct hostapd_ctrl *ctrl, int argc, char *argv[]);
|
||||
int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
|
||||
};
|
||||
|
||||
static struct hostapd_cli_cmd hostapd_cli_commands[] = {
|
||||
@ -373,7 +374,7 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = {
|
||||
};
|
||||
|
||||
|
||||
static void wpa_request(struct hostapd_ctrl *ctrl, int argc, char *argv[])
|
||||
static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
{
|
||||
struct hostapd_cli_cmd *cmd, *match = NULL;
|
||||
int count;
|
||||
@ -407,15 +408,15 @@ static void wpa_request(struct hostapd_ctrl *ctrl, int argc, char *argv[])
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_cli_recv_pending(struct hostapd_ctrl *ctrl, int in_read)
|
||||
static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read)
|
||||
{
|
||||
int first = 1;
|
||||
if (ctrl_conn == NULL)
|
||||
return;
|
||||
while (hostapd_ctrl_pending(ctrl)) {
|
||||
while (wpa_ctrl_pending(ctrl)) {
|
||||
char buf[256];
|
||||
size_t len = sizeof(buf) - 1;
|
||||
if (hostapd_ctrl_recv(ctrl, buf, &len) == 0) {
|
||||
if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
|
||||
buf[len] = '\0';
|
||||
if (in_read && first)
|
||||
printf("\n");
|
||||
@ -484,7 +485,7 @@ static void hostapd_cli_terminate(int sig)
|
||||
|
||||
static void hostapd_cli_alarm(int sig)
|
||||
{
|
||||
if (ctrl_conn && _hostapd_ctrl_command(ctrl_conn, "PING", 0)) {
|
||||
if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
|
||||
printf("Connection to hostapd lost - trying to reconnect\n");
|
||||
hostapd_cli_close_connection();
|
||||
}
|
||||
@ -492,7 +493,7 @@ static void hostapd_cli_alarm(int sig)
|
||||
ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
|
||||
if (ctrl_conn) {
|
||||
printf("Connection to hostapd re-established\n");
|
||||
if (hostapd_ctrl_attach(ctrl_conn) == 0) {
|
||||
if (wpa_ctrl_attach(ctrl_conn) == 0) {
|
||||
hostapd_cli_attached = 1;
|
||||
} else {
|
||||
printf("Warning: Failed to attach to "
|
||||
@ -568,7 +569,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
if (!interactive) {
|
||||
perror("Failed to connect to hostapd - "
|
||||
"hostapd_ctrl_open");
|
||||
"wpa_ctrl_open");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -585,7 +586,7 @@ int main(int argc, char *argv[])
|
||||
signal(SIGALRM, hostapd_cli_alarm);
|
||||
|
||||
if (interactive) {
|
||||
if (hostapd_ctrl_attach(ctrl_conn) == 0) {
|
||||
if (wpa_ctrl_attach(ctrl_conn) == 0) {
|
||||
hostapd_cli_attached = 1;
|
||||
} else {
|
||||
printf("Warning: Failed to attach to hostapd.\n");
|
||||
|
@ -53,6 +53,7 @@
|
||||
#include "iapp.h"
|
||||
#include "eloop.h"
|
||||
#include "sta_info.h"
|
||||
#include "hostap_common.h"
|
||||
|
||||
|
||||
#define IAPP_MULTICAST "224.0.1.178"
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <time.h>
|
||||
|
||||
@ -34,6 +35,7 @@
|
||||
#include "wpa.h"
|
||||
#include "accounting.h"
|
||||
#include "driver.h"
|
||||
#include "hostap_common.h"
|
||||
|
||||
|
||||
static u8 * hostapd_eid_supp_rates(hostapd *hapd, u8 *eid)
|
||||
@ -175,7 +177,7 @@ ParseRes ieee802_11_parse_elems(struct hostapd_data *hapd, u8 *start,
|
||||
}
|
||||
|
||||
|
||||
static void ieee802_11_print_ssid(u8 *ssid, u8 len)
|
||||
static void ieee802_11_print_ssid(const u8 *ssid, u8 len)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < len; i++) {
|
||||
@ -199,7 +201,8 @@ static void ieee802_11_sta_authenticate(void *eloop_ctx, void *timeout_ctx)
|
||||
|
||||
printf("Authenticate with AP " MACSTR " SSID=",
|
||||
MAC2STR(hapd->conf->assoc_ap_addr));
|
||||
ieee802_11_print_ssid(hapd->assoc_ap_ssid, hapd->assoc_ap_ssid_len);
|
||||
ieee802_11_print_ssid((u8 *) hapd->assoc_ap_ssid,
|
||||
hapd->assoc_ap_ssid_len);
|
||||
printf(" (as station)\n");
|
||||
|
||||
memset(&mgmt, 0, sizeof(mgmt));
|
||||
@ -236,7 +239,8 @@ static void ieee802_11_sta_associate(void *eloop_ctx, void *timeout_ctx)
|
||||
|
||||
printf("Associate with AP " MACSTR " SSID=",
|
||||
MAC2STR(hapd->conf->assoc_ap_addr));
|
||||
ieee802_11_print_ssid(hapd->assoc_ap_ssid, hapd->assoc_ap_ssid_len);
|
||||
ieee802_11_print_ssid((u8 *) hapd->assoc_ap_ssid,
|
||||
hapd->assoc_ap_ssid_len);
|
||||
printf(" (as station)\n");
|
||||
|
||||
memset(mgmt, 0, sizeof(*mgmt));
|
||||
@ -475,7 +479,7 @@ static void handle_auth(hostapd *hapd, struct ieee80211_mgmt *mgmt, size_t len)
|
||||
sta->flags &= ~WLAN_STA_PREAUTH;
|
||||
ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
|
||||
|
||||
if (hapd->conf->radius_acct_interim_interval == 0 &&
|
||||
if (hapd->conf->radius->acct_interim_interval == 0 &&
|
||||
acct_interim_interval)
|
||||
sta->acct_interim_interval = acct_interim_interval;
|
||||
if (res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
|
||||
@ -1091,10 +1095,7 @@ static void handle_assoc_cb(hostapd *hapd, struct ieee80211_mgmt *mgmt,
|
||||
}
|
||||
|
||||
wpa_sm_event(hapd, sta, WPA_ASSOC);
|
||||
if (new_assoc)
|
||||
hostapd_new_assoc_sta(hapd, sta);
|
||||
else
|
||||
wpa_sm_event(hapd, sta, WPA_REAUTH);
|
||||
hostapd_new_assoc_sta(hapd, sta, !new_assoc);
|
||||
|
||||
ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
|
||||
|
||||
@ -1139,6 +1140,7 @@ static void ieee80211_tkip_countermeasures_stop(void *eloop_ctx,
|
||||
{
|
||||
struct hostapd_data *hapd = eloop_ctx;
|
||||
hapd->tkip_countermeasures = 0;
|
||||
hostapd_set_countermeasures(hapd, 0);
|
||||
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_INFO, "TKIP countermeasures ended");
|
||||
}
|
||||
@ -1154,6 +1156,7 @@ static void ieee80211_tkip_countermeasures_start(struct hostapd_data *hapd)
|
||||
if (hapd->wpa_auth)
|
||||
hapd->wpa_auth->dot11RSNATKIPCounterMeasuresInvoked++;
|
||||
hapd->tkip_countermeasures = 1;
|
||||
hostapd_set_countermeasures(hapd, 1);
|
||||
wpa_gtk_rekey(hapd);
|
||||
eloop_cancel_timeout(ieee80211_tkip_countermeasures_stop, hapd, NULL);
|
||||
eloop_register_timeout(60, 0, ieee80211_tkip_countermeasures_stop,
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
@ -27,6 +28,7 @@
|
||||
#include "radius.h"
|
||||
#include "radius_client.h"
|
||||
#include "eloop.h"
|
||||
#include "hostap_common.h"
|
||||
|
||||
#define RADIUS_ACL_TIMEOUT 30
|
||||
|
||||
@ -121,18 +123,28 @@ static int hostapd_radius_acl_query(hostapd *hapd, u8 *addr,
|
||||
|
||||
if (!radius_msg_add_attr_user_password(
|
||||
msg, (u8 *) buf, strlen(buf),
|
||||
hapd->conf->auth_server->shared_secret,
|
||||
hapd->conf->auth_server->shared_secret_len)) {
|
||||
hapd->conf->radius->auth_server->shared_secret,
|
||||
hapd->conf->radius->auth_server->shared_secret_len)) {
|
||||
printf("Could not add User-Password\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
|
||||
(u8 *) &hapd->conf->own_ip_addr, 4)) {
|
||||
if (hapd->conf->own_ip_addr.af == AF_INET &&
|
||||
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
|
||||
(u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
|
||||
printf("Could not add NAS-IP-Address\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IPV6
|
||||
if (hapd->conf->own_ip_addr.af == AF_INET6 &&
|
||||
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
|
||||
(u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
|
||||
printf("Could not add NAS-IPv6-Address\n");
|
||||
goto fail;
|
||||
}
|
||||
#endif /* CONFIG_IPV6 */
|
||||
|
||||
if (hapd->conf->nas_identifier &&
|
||||
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
|
||||
(u8 *) hapd->conf->nas_identifier,
|
||||
@ -221,7 +233,7 @@ int hostapd_allowed_address(hostapd *hapd, u8 *addr, u8 *msg, size_t len,
|
||||
query = query->next;
|
||||
}
|
||||
|
||||
if (!hapd->conf->auth_server)
|
||||
if (!hapd->conf->radius->auth_server)
|
||||
return HOSTAPD_ACL_REJECT;
|
||||
|
||||
/* No entry in the cache - query external RADIUS server */
|
||||
@ -356,8 +368,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
|
||||
HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Found matching Access-Request "
|
||||
"for RADIUS message (id=%d)\n", query->radius_id);
|
||||
|
||||
if (radius_msg_verify_acct(msg, shared_secret, shared_secret_len,
|
||||
req)) {
|
||||
if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) {
|
||||
printf("Incoming RADIUS packet did not have correct "
|
||||
"authenticator - dropped\n");
|
||||
return RADIUS_RX_INVALID_AUTHENTICATOR;
|
||||
|
@ -133,13 +133,13 @@ void ieee802_1x_request_identity(struct hostapd_data *hapd,
|
||||
{
|
||||
u8 *buf;
|
||||
struct eap_hdr *eap;
|
||||
int extra, tlen;
|
||||
int tlen;
|
||||
u8 *pos;
|
||||
struct eapol_state_machine *sm = sta->eapol_sm;
|
||||
|
||||
if (hapd->conf->eap_authenticator) {
|
||||
if (hapd->conf->eap_server) {
|
||||
HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
|
||||
"IEEE 802.1X: Integrated EAP Authenticator in "
|
||||
"IEEE 802.1X: Integrated EAP server in "
|
||||
"use - do not generate EAP-Request/Identity\n");
|
||||
return;
|
||||
}
|
||||
@ -149,12 +149,7 @@ void ieee802_1x_request_identity(struct hostapd_data *hapd,
|
||||
|
||||
ieee802_1x_new_auth_session(hapd, sta);
|
||||
|
||||
if (hapd->conf->eap_req_id_text)
|
||||
extra = strlen(hapd->conf->eap_req_id_text);
|
||||
else
|
||||
extra = 0;
|
||||
|
||||
tlen = sizeof(*eap) + 1 + extra;
|
||||
tlen = sizeof(*eap) + 1 + hapd->conf->eap_req_id_text_len;
|
||||
|
||||
buf = malloc(tlen);
|
||||
if (buf == NULL) {
|
||||
@ -170,8 +165,10 @@ void ieee802_1x_request_identity(struct hostapd_data *hapd,
|
||||
eap->length = htons(tlen);
|
||||
pos = (u8 *) (eap + 1);
|
||||
*pos++ = EAP_TYPE_IDENTITY;
|
||||
if (hapd->conf->eap_req_id_text)
|
||||
memcpy(pos, hapd->conf->eap_req_id_text, extra);
|
||||
if (hapd->conf->eap_req_id_text) {
|
||||
memcpy(pos, hapd->conf->eap_req_id_text,
|
||||
hapd->conf->eap_req_id_text_len);
|
||||
}
|
||||
|
||||
sm->be_auth.eapReq = TRUE;
|
||||
free(sm->last_eap_radius);
|
||||
@ -422,12 +419,22 @@ static void ieee802_1x_encapsulate_radius(hostapd *hapd, struct sta_info *sta,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
|
||||
(u8 *) &hapd->conf->own_ip_addr, 4)) {
|
||||
if (hapd->conf->own_ip_addr.af == AF_INET &&
|
||||
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
|
||||
(u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
|
||||
printf("Could not add NAS-IP-Address\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IPV6
|
||||
if (hapd->conf->own_ip_addr.af == AF_INET6 &&
|
||||
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
|
||||
(u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
|
||||
printf("Could not add NAS-IPv6-Address\n");
|
||||
goto fail;
|
||||
}
|
||||
#endif /* CONFIG_IPV6 */
|
||||
|
||||
if (hapd->conf->nas_identifier &&
|
||||
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
|
||||
(u8 *) hapd->conf->nas_identifier,
|
||||
@ -663,7 +670,8 @@ static void handle_eap(hostapd *hapd, struct sta_info *sta, u8 *buf,
|
||||
|
||||
|
||||
/* Process the EAPOL frames from the Supplicant */
|
||||
void ieee802_1x_receive(hostapd *hapd, u8 *sa, u8 *buf, size_t len)
|
||||
void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct sta_info *sta;
|
||||
struct ieee802_1x_hdr *hdr;
|
||||
@ -798,20 +806,17 @@ void ieee802_1x_new_station(hostapd *hapd, struct sta_info *sta)
|
||||
if (!hapd->conf->ieee802_1x || sta->wpa_key_mgmt == WPA_KEY_MGMT_PSK)
|
||||
return;
|
||||
|
||||
if (sta->eapol_sm) {
|
||||
sta->eapol_sm->portEnabled = TRUE;
|
||||
eapol_sm_step(sta->eapol_sm);
|
||||
return;
|
||||
}
|
||||
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
|
||||
HOSTAPD_LEVEL_DEBUG, "start authentication");
|
||||
sta->eapol_sm = eapol_sm_alloc(hapd, sta);
|
||||
if (sta->eapol_sm == NULL) {
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
|
||||
HOSTAPD_LEVEL_INFO, "failed to allocate "
|
||||
"state machine");
|
||||
return;
|
||||
HOSTAPD_LEVEL_DEBUG, "start authentication");
|
||||
sta->eapol_sm = eapol_sm_alloc(hapd, sta);
|
||||
if (sta->eapol_sm == NULL) {
|
||||
hostapd_logger(hapd, sta->addr,
|
||||
HOSTAPD_MODULE_IEEE8021X,
|
||||
HOSTAPD_LEVEL_INFO,
|
||||
"failed to allocate state machine");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
sta->eapol_sm->portEnabled = TRUE;
|
||||
@ -827,7 +832,51 @@ void ieee802_1x_new_station(hostapd *hapd, struct sta_info *sta)
|
||||
sta->eapol_sm->auth_pae.state = AUTH_PAE_AUTHENTICATING;
|
||||
sta->eapol_sm->be_auth.state = BE_AUTH_SUCCESS;
|
||||
sta->eapol_sm->authSuccess = TRUE;
|
||||
if (sta->eapol_sm->eap)
|
||||
eap_sm_notify_cached(sta->eapol_sm->eap);
|
||||
} else
|
||||
eapol_sm_step(sta->eapol_sm);
|
||||
}
|
||||
|
||||
|
||||
void ieee802_1x_free_radius_class(struct radius_class_data *class)
|
||||
{
|
||||
int i;
|
||||
if (class == NULL)
|
||||
return;
|
||||
for (i = 0; i < class->count; i++)
|
||||
free(class->attr[i].data);
|
||||
free(class->attr);
|
||||
class->attr = NULL;
|
||||
class->count = 0;
|
||||
}
|
||||
|
||||
|
||||
int ieee802_1x_copy_radius_class(struct radius_class_data *dst,
|
||||
struct radius_class_data *src)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (src->attr == NULL)
|
||||
return 0;
|
||||
|
||||
dst->attr = malloc(src->count * sizeof(struct radius_attr_data));
|
||||
if (dst->attr == NULL)
|
||||
return -1;
|
||||
|
||||
memset(dst->attr, 0, src->count * sizeof(struct radius_attr_data));
|
||||
dst->count = 0;
|
||||
|
||||
for (i = 0; i < src->count; i++) {
|
||||
dst->attr[i].data = malloc(src->attr[i].len);
|
||||
if (dst->attr[i].data == NULL)
|
||||
break;
|
||||
dst->count++;
|
||||
memcpy(dst->attr[i].data, src->attr[i].data, src->attr[i].len);
|
||||
dst->attr[i].len = src->attr[i].len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -850,7 +899,7 @@ void ieee802_1x_free_station(struct sta_info *sta)
|
||||
free(sm->last_eap_supp);
|
||||
free(sm->last_eap_radius);
|
||||
free(sm->identity);
|
||||
free(sm->radius_class);
|
||||
ieee802_1x_free_radius_class(&sm->radius_class);
|
||||
free(sm->eapol_key_sign);
|
||||
free(sm->eapol_key_crypt);
|
||||
eapol_sm_free(sm);
|
||||
@ -993,31 +1042,87 @@ static void ieee802_1x_store_radius_class(struct hostapd_data *hapd,
|
||||
u8 *class;
|
||||
size_t class_len;
|
||||
struct eapol_state_machine *sm = sta->eapol_sm;
|
||||
int count, i;
|
||||
struct radius_attr_data *nclass;
|
||||
size_t nclass_count;
|
||||
|
||||
if (!hapd->conf->acct_server || hapd->radius == NULL || sm == NULL)
|
||||
if (!hapd->conf->radius->acct_server || hapd->radius == NULL ||
|
||||
sm == NULL)
|
||||
return;
|
||||
|
||||
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CLASS, &class,
|
||||
&class_len) < 0 ||
|
||||
class_len < 1) {
|
||||
free(sm->radius_class);
|
||||
sm->radius_class = NULL;
|
||||
sm->radius_class_len = 0;
|
||||
ieee802_1x_free_radius_class(&sm->radius_class);
|
||||
count = radius_msg_count_attr(msg, RADIUS_ATTR_CLASS, 1);
|
||||
if (count <= 0)
|
||||
return;
|
||||
|
||||
nclass = malloc(count * sizeof(struct radius_attr_data));
|
||||
if (nclass == NULL)
|
||||
return;
|
||||
|
||||
nclass_count = 0;
|
||||
memset(nclass, 0, count * sizeof(struct radius_attr_data));
|
||||
|
||||
class = NULL;
|
||||
for (i = 0; i < count; i++) {
|
||||
do {
|
||||
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CLASS,
|
||||
&class, &class_len,
|
||||
class) < 0) {
|
||||
i = count;
|
||||
break;
|
||||
}
|
||||
} while (class_len < 1);
|
||||
|
||||
nclass[nclass_count].data = malloc(class_len);
|
||||
if (nclass[nclass_count].data == NULL)
|
||||
break;
|
||||
|
||||
memcpy(nclass[nclass_count].data, class, class_len);
|
||||
nclass[nclass_count].len = class_len;
|
||||
nclass_count++;
|
||||
}
|
||||
|
||||
if (sm->radius_class == NULL ||
|
||||
sm->radius_class_len < class_len) {
|
||||
free(sm->radius_class);
|
||||
sm->radius_class = malloc(class_len);
|
||||
if (sm->radius_class == NULL) {
|
||||
sm->radius_class_len = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
sm->radius_class.attr = nclass;
|
||||
sm->radius_class.count = nclass_count;
|
||||
HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "IEEE 802.1X: Stored %lu RADIUS "
|
||||
"Class attributes for " MACSTR "\n",
|
||||
(unsigned long) sm->radius_class.count,
|
||||
MAC2STR(sta->addr));
|
||||
}
|
||||
|
||||
memcpy(sm->radius_class, class, class_len);
|
||||
sm->radius_class_len = class_len;
|
||||
|
||||
/* Update sta->identity based on User-Name attribute in Access-Accept */
|
||||
static void ieee802_1x_update_sta_identity(struct hostapd_data *hapd,
|
||||
struct sta_info *sta,
|
||||
struct radius_msg *msg)
|
||||
{
|
||||
u8 *buf, *identity;
|
||||
size_t len;
|
||||
struct eapol_state_machine *sm = sta->eapol_sm;
|
||||
|
||||
if (sm == NULL)
|
||||
return;
|
||||
|
||||
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, &buf, &len,
|
||||
NULL) < 0)
|
||||
return;
|
||||
|
||||
identity = malloc(len + 1);
|
||||
if (identity == NULL)
|
||||
return;
|
||||
|
||||
memcpy(identity, buf, len);
|
||||
identity[len] = '\0';
|
||||
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
|
||||
HOSTAPD_LEVEL_DEBUG, "old identity '%s' updated with "
|
||||
"User-Name from Access-Accept '%s'",
|
||||
sm->identity ? (char *) sm->identity : "N/A",
|
||||
(char *) identity);
|
||||
|
||||
free(sm->identity);
|
||||
sm->identity = identity;
|
||||
sm->identity_len = len;
|
||||
}
|
||||
|
||||
|
||||
@ -1062,7 +1167,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
|
||||
{
|
||||
struct hostapd_data *hapd = data;
|
||||
struct sta_info *sta;
|
||||
u32 session_timeout, termination_action, acct_interim_interval;
|
||||
u32 session_timeout = 0, termination_action, acct_interim_interval;
|
||||
int session_timeout_set;
|
||||
int eap_timeout;
|
||||
struct eapol_state_machine *sm;
|
||||
@ -1087,7 +1192,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
|
||||
"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_INVALID_AUTHENTICATOR;
|
||||
@ -1119,7 +1224,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
|
||||
&termination_action))
|
||||
termination_action = RADIUS_TERMINATION_ACTION_DEFAULT;
|
||||
|
||||
if (hapd->conf->radius_acct_interim_interval == 0 &&
|
||||
if (hapd->conf->radius->acct_interim_interval == 0 &&
|
||||
msg->hdr->code == RADIUS_CODE_ACCESS_ACCEPT &&
|
||||
radius_msg_get_attr_int32(msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL,
|
||||
&acct_interim_interval) == 0) {
|
||||
@ -1148,12 +1253,13 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
|
||||
override_eapReq = 1;
|
||||
ieee802_1x_get_keys(hapd, sta, msg, req, shared_secret,
|
||||
shared_secret_len);
|
||||
ieee802_1x_store_radius_class(hapd, sta, msg);
|
||||
ieee802_1x_update_sta_identity(hapd, sta, msg);
|
||||
if (sm->keyAvailable) {
|
||||
pmksa_cache_add(hapd, sta, sm->eapol_key_crypt,
|
||||
session_timeout_set ?
|
||||
session_timeout : -1);
|
||||
}
|
||||
ieee802_1x_store_radius_class(hapd, sta, msg);
|
||||
break;
|
||||
case RADIUS_CODE_ACCESS_REJECT:
|
||||
sm->eapFail = TRUE;
|
||||
@ -1195,7 +1301,7 @@ void ieee802_1x_send_resp_to_server(hostapd *hapd, struct sta_info *sta)
|
||||
if (sm == NULL)
|
||||
return;
|
||||
|
||||
if (hapd->conf->eap_authenticator) {
|
||||
if (hapd->conf->eap_server) {
|
||||
eap_set_eapRespData(sm->eap, sm->last_eap_supp,
|
||||
sm->last_eap_supp_len);
|
||||
} else {
|
||||
@ -1225,9 +1331,6 @@ void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
free(sm->last_eap_radius);
|
||||
sm->last_eap_radius = NULL;
|
||||
sm->last_eap_radius_len = 0;
|
||||
free(sm->radius_class);
|
||||
sm->radius_class = NULL;
|
||||
sm->radius_class_len = 0;
|
||||
}
|
||||
|
||||
|
||||
@ -1478,13 +1581,15 @@ u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len)
|
||||
}
|
||||
|
||||
|
||||
u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len)
|
||||
u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
|
||||
int idx)
|
||||
{
|
||||
if (sm == NULL || sm->radius_class == NULL)
|
||||
if (sm == NULL || sm->radius_class.attr == NULL ||
|
||||
idx >= sm->radius_class.count)
|
||||
return NULL;
|
||||
|
||||
*len = sm->radius_class_len;
|
||||
return sm->radius_class;
|
||||
*len = sm->radius_class.attr[idx].len;
|
||||
return sm->radius_class.attr[idx].data;
|
||||
}
|
||||
|
||||
|
||||
@ -1504,6 +1609,7 @@ void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm,
|
||||
if (sm == NULL)
|
||||
return;
|
||||
sm->portEnabled = enabled ? TRUE : FALSE;
|
||||
eapol_sm_step(sm);
|
||||
}
|
||||
|
||||
|
||||
@ -1513,6 +1619,7 @@ void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm,
|
||||
if (sm == NULL)
|
||||
return;
|
||||
sm->portValid = valid ? TRUE : FALSE;
|
||||
eapol_sm_step(sm);
|
||||
}
|
||||
|
||||
|
||||
|
@ -47,7 +47,8 @@ enum { EAPOL_KEY_TYPE_RC4 = 1, EAPOL_KEY_TYPE_RSN = 2,
|
||||
EAPOL_KEY_TYPE_WPA = 254 };
|
||||
|
||||
|
||||
void ieee802_1x_receive(hostapd *hapd, u8 *sa, u8 *buf, size_t len);
|
||||
void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
|
||||
size_t len);
|
||||
void ieee802_1x_new_station(hostapd *hapd, struct sta_info *sta);
|
||||
void ieee802_1x_free_station(struct sta_info *sta);
|
||||
|
||||
@ -69,7 +70,8 @@ void ieee802_1x_deinit(hostapd *hapd);
|
||||
int ieee802_1x_tx_status(hostapd *hapd, struct sta_info *sta, u8 *buf,
|
||||
size_t len, int ack);
|
||||
u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len);
|
||||
u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len);
|
||||
u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
|
||||
int idx);
|
||||
u8 * ieee802_1x_get_key_crypt(struct eapol_state_machine *sm, size_t *len);
|
||||
void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm,
|
||||
int enabled);
|
||||
@ -83,4 +85,10 @@ void hostapd_get_ntp_timestamp(u8 *buf);
|
||||
void ieee802_1x_finished(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
int success);
|
||||
|
||||
struct radius_class_data;
|
||||
|
||||
void ieee802_1x_free_radius_class(struct radius_class_data *class);
|
||||
int ieee802_1x_copy_radius_class(struct radius_class_data *dst,
|
||||
struct radius_class_data *src);
|
||||
|
||||
#endif /* IEEE802_1X_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 */
|
||||
|
9
contrib/hostapd/logwatch/README
Normal file
9
contrib/hostapd/logwatch/README
Normal file
@ -0,0 +1,9 @@
|
||||
Logwatch is a utility for analyzing system logs and provide a human
|
||||
readable summary. This directory has a configuration file and a log
|
||||
analyzer script for parsing hostapd system log entries for logwatch.
|
||||
These files can be installed by copying them to following locations:
|
||||
|
||||
/etc/log.d/conf/services/hostapd.conf
|
||||
/etc/log.d/scripts/services/hostapd
|
||||
|
||||
More information about logwatch is available from http://www.logwatch.org/
|
65
contrib/hostapd/logwatch/hostapd
Executable file
65
contrib/hostapd/logwatch/hostapd
Executable file
@ -0,0 +1,65 @@
|
||||
#!/usr/bin/perl -w
|
||||
#
|
||||
# Logwatch script for hostapd
|
||||
#
|
||||
# Copyright 2005 Henrik Brix Andersen <brix@gentoo.org>
|
||||
# Distributed under the terms of the GNU General Public License v2
|
||||
# Alternatively, this file may be distributed under the terms of the BSD License
|
||||
|
||||
use strict;
|
||||
|
||||
my $debug = $ENV{'LOGWATCH_DEBUG'} || 0;
|
||||
my $detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0;
|
||||
my $debugcounter = 1;
|
||||
|
||||
my %hostapd;
|
||||
my @unmatched;
|
||||
|
||||
if ($debug >= 5) {
|
||||
print STDERR "\n\nDEBUG: Inside HOSTAPD Filter\n\n";
|
||||
}
|
||||
|
||||
while (defined(my $line = <STDIN>)) {
|
||||
if ($debug >= 5) {
|
||||
print STDERR "DEBUG($debugcounter): $line";
|
||||
$debugcounter++;
|
||||
}
|
||||
chomp($line);
|
||||
|
||||
if (my ($iface,$mac,$layer,$details) = ($line =~ /(.*?): STA (.*?) (.*?): (.*?)$/i)) {
|
||||
unless ($detail == 10) {
|
||||
# collapse association events
|
||||
$details =~ s/^(associated) .*$/$1/i;
|
||||
}
|
||||
$hostapd{$iface}->{$mac}->{$layer}->{$details}++;
|
||||
} else {
|
||||
push @unmatched, "$line\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (keys %hostapd) {
|
||||
foreach my $iface (sort keys %hostapd) {
|
||||
print "Interface $iface:\n";
|
||||
foreach my $mac (sort keys %{$hostapd{$iface}}) {
|
||||
print " Client MAC Address $mac:\n";
|
||||
foreach my $layer (sort keys %{$hostapd{$iface}->{$mac}}) {
|
||||
print " $layer:\n";
|
||||
foreach my $details (sort keys %{$hostapd{$iface}->{$mac}->{$layer}}) {
|
||||
print " $details";
|
||||
my $count = $hostapd{$iface}->{$mac}->{$layer}->{$details};
|
||||
if ($count > 1) {
|
||||
print ": " . $count . " Times";
|
||||
}
|
||||
print "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($#unmatched >= 0) {
|
||||
print "\n**Unmatched Entries**\n";
|
||||
print @unmatched;
|
||||
}
|
||||
|
||||
exit(0);
|
10
contrib/hostapd/logwatch/hostapd.conf
Normal file
10
contrib/hostapd/logwatch/hostapd.conf
Normal file
@ -0,0 +1,10 @@
|
||||
# Logwatch configuration for hostapd
|
||||
#
|
||||
# Copyright 2005 Henrik Brix Andersen <brix@gentoo.org>
|
||||
# Distributed under the terms of the GNU General Public License v2
|
||||
# Alternatively, this file may be distributed under the terms of the BSD License
|
||||
|
||||
Title = "hostapd"
|
||||
LogFile = messages
|
||||
*OnlyService = hostapd
|
||||
*RemoveHeaders
|
@ -4,6 +4,10 @@
|
||||
# AP netdevice name (without 'ap' prefix, i.e., wlan0 uses wlan0ap for
|
||||
# management frames)
|
||||
interface=ath0
|
||||
|
||||
# In case of madwifi driver, an additional configuration parameter, bridge,
|
||||
# must be used to notify hostapd if the interface is included in a bridge. This
|
||||
# parameter is not used with Host AP driver.
|
||||
bridge=br0
|
||||
|
||||
# Driver interface type (hostap/wired/madwifi; default: hostap)
|
||||
@ -21,6 +25,7 @@ driver=madwifi
|
||||
# bit 2 (4) = RADIUS
|
||||
# bit 3 (8) = WPA
|
||||
# bit 4 (16) = driver interface
|
||||
# bit 5 (32) = IAPP
|
||||
#
|
||||
# Levels (minimum value for logged events):
|
||||
# 0 = verbose debugging
|
||||
@ -46,21 +51,17 @@ dump_file=/tmp/hostapd.dump
|
||||
# SSID to be used in IEEE 802.11 management frames
|
||||
ssid=wpa-test
|
||||
|
||||
##### IEEE 802.1X (and IEEE 802.1aa/D4) related configuration #################
|
||||
##### IEEE 802.1X-REV related configuration ###################################
|
||||
|
||||
# Require IEEE 802.1X authorization
|
||||
#ieee8021x=1
|
||||
|
||||
# Use internal minimal EAP Authentication Server for testing IEEE 802.1X.
|
||||
# This should only be used for testing since it authorizes all users that
|
||||
# support IEEE 802.1X without any keys or certificates. Please also note that
|
||||
# the EAP method used with this minimal server does not generate any keying
|
||||
# material and as such, it cannot be used with dynamic WEP keying
|
||||
# (wep_key_len_broadcast and wep_key_len_unicast).
|
||||
minimal_eap=0
|
||||
|
||||
# Optional displayable message sent with EAP Request-Identity
|
||||
eap_message=hello
|
||||
# Optional displayable message sent with EAP Request-Identity. The first \0
|
||||
# in this string will be converted to ASCII-0 (nul). This can be used to
|
||||
# separate network info (comma separated list of attribute=value pairs); see,
|
||||
# e.g., draft-adrangi-eap-network-discovery-07.txt.
|
||||
#eap_message=hello
|
||||
#eap_message=hello\0networkid=netw,nasid=foo,portid=0,NAIRealms=example.com
|
||||
|
||||
# WEP rekeying (disabled if key lengths are not set or are set to 0)
|
||||
# Key lengths for default/broadcast and individual/unicast keys:
|
||||
@ -79,13 +80,63 @@ eapol_key_index_workaround=0
|
||||
# reauthentication).
|
||||
#eap_reauth_period=3600
|
||||
|
||||
|
||||
##### Integrated EAP server ###################################################
|
||||
|
||||
# Optionally, hostapd can be configured to use an integrated EAP server
|
||||
# to process EAP authentication locally without need for an external RADIUS
|
||||
# server. This functionality can be used both as a local authentication server
|
||||
# for IEEE 802.1X/EAPOL and as a RADIUS server for other devices.
|
||||
|
||||
# Use integrated EAP server instead of external RADIUS authentication
|
||||
# server. This is also needed if hostapd is configured to act as a RADIUS
|
||||
# authentication server.
|
||||
eap_server=0
|
||||
|
||||
# Path for EAP server user database
|
||||
#eap_user_file=/etc/hostapd.eap_user
|
||||
|
||||
# CA certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS
|
||||
#ca_cert=/etc/hostapd.ca.pem
|
||||
|
||||
# Server certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS
|
||||
#server_cert=/etc/hostapd.server.pem
|
||||
|
||||
# Private key matching with the server certificate for EAP-TLS/PEAP/TTLS
|
||||
# This may point to the same file as server_cert if both certificate and key
|
||||
# are included in a single file. PKCS#12 (PFX) file (.p12/.pfx) can also be
|
||||
# used by commenting out server_cert and specifying the PFX file as the
|
||||
# private_key.
|
||||
#private_key=/etc/hostapd.server.prv
|
||||
|
||||
# Passphrase for private key
|
||||
#private_key_passwd=secret passphrase
|
||||
|
||||
# Enable CRL verification.
|
||||
# Note: hostapd does not yet support CRL downloading based on CDP. Thus, a
|
||||
# valid CRL signed by the CA is required to be included in the ca_cert file.
|
||||
# This can be done by using PEM format for CA certificate and CRL and
|
||||
# concatenating these into one file. Whenever CRL changes, hostapd needs to be
|
||||
# restarted to take the new CRL into use.
|
||||
# 0 = do not verify CRLs (default)
|
||||
# 1 = check the CRL of the user certificate
|
||||
# 2 = check all CRLs in the certificate path
|
||||
#check_crl=1
|
||||
|
||||
# Configuration data for EAP-SIM database/authentication gateway interface.
|
||||
# This is a text string in implementation specific format. The example
|
||||
# implementation in eap_sim_db.c uses this as the file name for the GSM
|
||||
# authentication triplets.
|
||||
#eap_sim_db=/etc/hostapd.sim_db
|
||||
|
||||
|
||||
##### IEEE 802.11f - Inter-Access Point Protocol (IAPP) #######################
|
||||
|
||||
# Interface to be used for IAPP broadcast packets
|
||||
#iapp_interface=eth0
|
||||
|
||||
|
||||
##### RADIUS configuration ####################################################
|
||||
##### RADIUS client configuration #############################################
|
||||
# for IEEE 802.1X with external Authentication Server, IEEE 802.11
|
||||
# authentication with external ACL for MAC addresses, and accounting
|
||||
|
||||
@ -137,6 +188,23 @@ own_ip_addr=127.0.0.1
|
||||
#radius_acct_interim_interval=600
|
||||
|
||||
|
||||
##### RADIUS authentication server configuration ##############################
|
||||
|
||||
# hostapd can be used as a RADIUS authentication server for other hosts. This
|
||||
# requires that the integrated EAP authenticator is also enabled and both
|
||||
# authentication services are sharing the same configuration.
|
||||
|
||||
# File name of the RADIUS clients configuration for the RADIUS server. If this
|
||||
# commented out, RADIUS server is disabled.
|
||||
#radius_server_clients=/etc/hostapd.radius_clients
|
||||
|
||||
# The UDP port number for the RADIUS authentication server
|
||||
#radius_server_auth_port=1812
|
||||
|
||||
# Use IPv6 with RADIUS server (IPv4 will also be supported using IPv6 API)
|
||||
#radius_server_ipv6=1
|
||||
|
||||
|
||||
##### WPA/IEEE 802.11i configuration ##########################################
|
||||
|
||||
# Enable WPA. Setting this variable configures the AP to require WPA (either
|
||||
@ -148,13 +216,15 @@ own_ip_addr=127.0.0.1
|
||||
# This field is a bit field that can be used to enable WPA (IEEE 802.11i/D3.0)
|
||||
# and/or WPA2 (full IEEE 802.11i/RSN):
|
||||
# bit0 = WPA
|
||||
# bit1 = IEEE 802.11i/RSN (WPA2)
|
||||
# bit1 = IEEE 802.11i/RSN (WPA2) (dot11RSNAEnabled)
|
||||
#wpa=1
|
||||
|
||||
# WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit
|
||||
# secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase
|
||||
# (8..63 characters) that will be converted to PSK. This conversion uses SSID
|
||||
# so the PSK changed when ASCII passphrase is used and the SSID is changed.
|
||||
# so the PSK changes when ASCII passphrase is used and the SSID is changed.
|
||||
# wpa_psk (dot11RSNAConfigPSKValue)
|
||||
# wpa_passphrase (dot11RSNAConfigPSKPassPhrase)
|
||||
#wpa_psk=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
|
||||
#wpa_passphrase=secret passphrase
|
||||
|
||||
@ -166,6 +236,7 @@ own_ip_addr=127.0.0.1
|
||||
|
||||
# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
|
||||
# entries are separated with a space.
|
||||
# (dot11RSNAConfigAuthenticationSuitesTable)
|
||||
#wpa_key_mgmt=WPA-PSK WPA-EAP
|
||||
|
||||
# Set of accepted cipher suites (encryption algorithms) for pairwise keys
|
||||
@ -176,12 +247,17 @@ own_ip_addr=127.0.0.1
|
||||
# is automatically selected based on this configuration. If only CCMP is
|
||||
# allowed as the pairwise cipher, group cipher will also be CCMP. Otherwise,
|
||||
# TKIP will be used as the group cipher.
|
||||
# (dot11RSNAConfigPairwiseCiphersTable)
|
||||
#wpa_pairwise=TKIP CCMP
|
||||
|
||||
# Time interval for rekeying GTK (broadcast/multicast encryption keys) in
|
||||
# seconds.
|
||||
# seconds. (dot11RSNAConfigGroupRekeyTime)
|
||||
#wpa_group_rekey=600
|
||||
|
||||
# Rekey GTK when any STA that possesses the current GTK is leaving the BSS.
|
||||
# (dot11RSNAConfigGroupRekeyStrict)
|
||||
#wpa_strict_rekey=1
|
||||
|
||||
# Time interval for rekeying GMK (master key used internally to generate GTKs
|
||||
# (in seconds).
|
||||
#wpa_gmk_rekey=86400
|
||||
@ -189,6 +265,7 @@ own_ip_addr=127.0.0.1
|
||||
# Enable IEEE 802.11i/RSN/WPA2 pre-authentication. This is used to speed up
|
||||
# roaming be pre-authenticating IEEE 802.1X/EAP part of the full RSN
|
||||
# authentication and key handshake before actually associating with a new AP.
|
||||
# (dot11RSNAPreauthenticationEnabled)
|
||||
#rsn_preauth=1
|
||||
#
|
||||
# Space separated list of interfaces from which pre-authentication frames are
|
||||
|
@ -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 */
|
||||
|
@ -16,18 +16,20 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <signal.h>
|
||||
#include <sys/time.h>
|
||||
#ifndef CONFIG_NATIVE_WINDOWS
|
||||
#include <netinet/in.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#endif /* CONFIG_NATIVE_WINDOWS */
|
||||
|
||||
#include "common.h"
|
||||
#include "radius.h"
|
||||
#include "md5.h"
|
||||
#include "crypto.h"
|
||||
|
||||
|
||||
struct radius_msg *radius_msg_new(u8 code, u8 identifier)
|
||||
@ -124,8 +126,10 @@ static const char *radius_code_string(u8 code)
|
||||
struct radius_attr_type {
|
||||
u8 type;
|
||||
char *name;
|
||||
enum { RADIUS_ATTR_UNDIST, RADIUS_ATTR_TEXT, RADIUS_ATTR_IP,
|
||||
RADIUS_ATTR_HEXDUMP, RADIUS_ATTR_INT32 } data_type;
|
||||
enum {
|
||||
RADIUS_ATTR_UNDIST, RADIUS_ATTR_TEXT, RADIUS_ATTR_IP,
|
||||
RADIUS_ATTR_HEXDUMP, RADIUS_ATTR_INT32, RADIUS_ATTR_IPV6
|
||||
} data_type;
|
||||
};
|
||||
|
||||
static struct radius_attr_type radius_attrs[] =
|
||||
@ -179,8 +183,8 @@ static struct radius_attr_type radius_attrs[] =
|
||||
{ RADIUS_ATTR_MESSAGE_AUTHENTICATOR, "Message-Authenticator",
|
||||
RADIUS_ATTR_UNDIST },
|
||||
{ RADIUS_ATTR_ACCT_INTERIM_INTERVAL, "Acct-Interim-Interval",
|
||||
RADIUS_ATTR_INT32 }
|
||||
|
||||
RADIUS_ATTR_INT32 },
|
||||
{ RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 },
|
||||
};
|
||||
#define RADIUS_ATTRS (sizeof(radius_attrs) / sizeof(radius_attrs[0]))
|
||||
|
||||
@ -231,6 +235,19 @@ static void radius_msg_dump_attr(struct radius_attr_hdr *hdr)
|
||||
printf(" Invalid IP address length %d\n", len);
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_IPV6
|
||||
case RADIUS_ATTR_IPV6:
|
||||
if (len == 16) {
|
||||
char buf[128];
|
||||
const char *atxt;
|
||||
struct in6_addr *addr = (struct in6_addr *) pos;
|
||||
atxt = inet_ntop(AF_INET6, addr, buf, sizeof(buf));
|
||||
printf(" Value: %s\n", atxt ? atxt : "?");
|
||||
} else
|
||||
printf(" Invalid IPv6 address length %d\n", len);
|
||||
break;
|
||||
#endif /* CONFIG_IPV6 */
|
||||
|
||||
case RADIUS_ATTR_HEXDUMP:
|
||||
case RADIUS_ATTR_UNDIST:
|
||||
printf(" Value:");
|
||||
@ -242,7 +259,8 @@ static void radius_msg_dump_attr(struct radius_attr_hdr *hdr)
|
||||
case RADIUS_ATTR_INT32:
|
||||
if (len == 4) {
|
||||
u32 *val = (u32 *) pos;
|
||||
printf(" Value: %d\n", ntohl(*val));
|
||||
printf(" Value: %u\n",
|
||||
(unsigned int) ntohl(*val));
|
||||
} else
|
||||
printf(" Invalid INT32 length %d\n", len);
|
||||
break;
|
||||
@ -302,7 +320,8 @@ int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret,
|
||||
{
|
||||
u8 auth[MD5_MAC_LEN];
|
||||
struct radius_attr_hdr *attr;
|
||||
MD5_CTX context;
|
||||
const u8 *addr[4];
|
||||
size_t len[4];
|
||||
|
||||
memset(auth, 0, MD5_MAC_LEN);
|
||||
attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
|
||||
@ -318,13 +337,15 @@ int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret,
|
||||
(u8 *) (attr + 1));
|
||||
|
||||
/* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
|
||||
MD5Init(&context);
|
||||
MD5Update(&context, (u8 *) msg->hdr, 1 + 1 + 2);
|
||||
MD5Update(&context, req_authenticator, MD5_MAC_LEN);
|
||||
MD5Update(&context, (u8 *) (msg->hdr + 1),
|
||||
msg->buf_used - sizeof(*msg->hdr));
|
||||
MD5Update(&context, secret, secret_len);
|
||||
MD5Final(msg->hdr->authenticator, &context);
|
||||
addr[0] = (u8 *) msg->hdr;
|
||||
len[0] = 1 + 1 + 2;
|
||||
addr[1] = req_authenticator;
|
||||
len[1] = MD5_MAC_LEN;
|
||||
addr[2] = (u8 *) (msg->hdr + 1);
|
||||
len[2] = msg->buf_used - sizeof(*msg->hdr);
|
||||
addr[3] = secret;
|
||||
len[3] = secret_len;
|
||||
md5_vector(4, addr, len, msg->hdr->authenticator);
|
||||
|
||||
if (msg->buf_used > 0xffff) {
|
||||
printf("WARNING: too long RADIUS message (%lu)\n",
|
||||
@ -338,14 +359,16 @@ int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret,
|
||||
void radius_msg_finish_acct(struct radius_msg *msg, u8 *secret,
|
||||
size_t secret_len)
|
||||
{
|
||||
MD5_CTX context;
|
||||
const u8 *addr[2];
|
||||
size_t len[2];
|
||||
|
||||
msg->hdr->length = htons(msg->buf_used);
|
||||
memset(msg->hdr->authenticator, 0, MD5_MAC_LEN);
|
||||
MD5Init(&context);
|
||||
MD5Update(&context, msg->buf, msg->buf_used);
|
||||
MD5Update(&context, secret, secret_len);
|
||||
MD5Final(msg->hdr->authenticator, &context);
|
||||
addr[0] = msg->buf;
|
||||
len[0] = msg->buf_used;
|
||||
addr[1] = secret;
|
||||
len[1] = secret_len;
|
||||
md5_vector(2, addr, len, msg->hdr->authenticator);
|
||||
|
||||
if (msg->buf_used > 0xffff) {
|
||||
printf("WARNING: too long RADIUS messages (%lu)\n",
|
||||
@ -378,7 +401,7 @@ static int radius_msg_add_attr_to_array(struct radius_msg *msg,
|
||||
|
||||
|
||||
struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type,
|
||||
u8 *data, size_t data_len)
|
||||
const u8 *data, size_t data_len)
|
||||
{
|
||||
size_t buf_needed;
|
||||
struct radius_attr_hdr *attr;
|
||||
@ -493,9 +516,9 @@ struct radius_msg *radius_msg_parse(const u8 *data, size_t len)
|
||||
}
|
||||
|
||||
|
||||
int radius_msg_add_eap(struct radius_msg *msg, u8 *data, size_t data_len)
|
||||
int radius_msg_add_eap(struct radius_msg *msg, const u8 *data, size_t data_len)
|
||||
{
|
||||
u8 *pos = data;
|
||||
const u8 *pos = data;
|
||||
size_t left = data_len;
|
||||
|
||||
while (left > 0) {
|
||||
@ -605,10 +628,11 @@ int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret,
|
||||
}
|
||||
|
||||
|
||||
int radius_msg_verify(struct radius_msg *msg, u8 *secret, size_t secret_len,
|
||||
struct radius_msg *sent_msg)
|
||||
int radius_msg_verify(struct radius_msg *msg, const u8 *secret,
|
||||
size_t secret_len, struct radius_msg *sent_msg, int auth)
|
||||
{
|
||||
MD5_CTX context;
|
||||
const u8 *addr[4];
|
||||
size_t len[4];
|
||||
u8 hash[MD5_MAC_LEN];
|
||||
|
||||
if (sent_msg == NULL) {
|
||||
@ -616,19 +640,22 @@ int radius_msg_verify(struct radius_msg *msg, u8 *secret, size_t secret_len,
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (radius_msg_verify_msg_auth(msg, secret, secret_len,
|
||||
if (auth &&
|
||||
radius_msg_verify_msg_auth(msg, secret, secret_len,
|
||||
sent_msg->hdr->authenticator)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
|
||||
MD5Init(&context);
|
||||
MD5Update(&context, (u8 *) msg->hdr, 1 + 1 + 2);
|
||||
MD5Update(&context, sent_msg->hdr->authenticator, MD5_MAC_LEN);
|
||||
MD5Update(&context, (u8 *) (msg->hdr + 1),
|
||||
msg->buf_used - sizeof(*msg->hdr));
|
||||
MD5Update(&context, secret, secret_len);
|
||||
MD5Final(hash, &context);
|
||||
addr[0] = (u8 *) msg->hdr;
|
||||
len[0] = 1 + 1 + 2;
|
||||
addr[1] = sent_msg->hdr->authenticator;
|
||||
len[1] = MD5_MAC_LEN;
|
||||
addr[2] = (u8 *) (msg->hdr + 1);
|
||||
len[2] = msg->buf_used - sizeof(*msg->hdr);
|
||||
addr[3] = secret;
|
||||
len[3] = secret_len;
|
||||
md5_vector(4, addr, len, hash);
|
||||
if (memcmp(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) {
|
||||
printf("Response Authenticator invalid!\n");
|
||||
return 1;
|
||||
@ -639,29 +666,6 @@ int radius_msg_verify(struct radius_msg *msg, u8 *secret, size_t secret_len,
|
||||
}
|
||||
|
||||
|
||||
int radius_msg_verify_acct(struct radius_msg *msg, u8 *secret,
|
||||
size_t secret_len, struct radius_msg *sent_msg)
|
||||
{
|
||||
MD5_CTX context;
|
||||
u8 hash[MD5_MAC_LEN];
|
||||
|
||||
MD5Init(&context);
|
||||
MD5Update(&context, msg->buf, 4);
|
||||
MD5Update(&context, sent_msg->hdr->authenticator, MD5_MAC_LEN);
|
||||
if (msg->buf_used > sizeof(struct radius_hdr))
|
||||
MD5Update(&context, msg->buf + sizeof(struct radius_hdr),
|
||||
msg->buf_used - sizeof(struct radius_hdr));
|
||||
MD5Update(&context, secret, secret_len);
|
||||
MD5Final(hash, &context);
|
||||
if (memcmp(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) {
|
||||
printf("Response Authenticator invalid!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src,
|
||||
u8 type)
|
||||
{
|
||||
@ -694,16 +698,19 @@ void radius_msg_make_authenticator(struct radius_msg *msg,
|
||||
u8 *data, size_t len)
|
||||
{
|
||||
struct timeval tv;
|
||||
MD5_CTX context;
|
||||
long int l;
|
||||
const u8 *addr[3];
|
||||
size_t elen[3];
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
l = random();
|
||||
MD5Init(&context);
|
||||
MD5Update(&context, (u8 *) &tv, sizeof(tv));
|
||||
MD5Update(&context, data, len);
|
||||
MD5Update(&context, (u8 *) &l, sizeof(l));
|
||||
MD5Final(msg->hdr->authenticator, &context);
|
||||
addr[0] = (u8 *) &tv;
|
||||
elen[0] = sizeof(tv);
|
||||
addr[1] = data;
|
||||
elen[1] = len;
|
||||
addr[2] = (u8 *) &l;
|
||||
elen[2] = sizeof(l);
|
||||
md5_vector(3, addr, elen, msg->hdr->authenticator);
|
||||
}
|
||||
|
||||
|
||||
@ -780,8 +787,9 @@ static u8 * decrypt_ms_key(const u8 *key, size_t len,
|
||||
const u8 *pos;
|
||||
size_t left, plen;
|
||||
u8 hash[MD5_MAC_LEN];
|
||||
MD5_CTX context;
|
||||
int i, first = 1;
|
||||
const u8 *addr[3];
|
||||
size_t elen[3];
|
||||
|
||||
/* key: 16-bit salt followed by encrypted key info */
|
||||
|
||||
@ -804,15 +812,19 @@ static u8 * decrypt_ms_key(const u8 *key, size_t len,
|
||||
/* b(1) = MD5(Secret + Request-Authenticator + Salt)
|
||||
* b(i) = MD5(Secret + c(i - 1)) for i > 1 */
|
||||
|
||||
MD5Init(&context);
|
||||
MD5Update(&context, secret, secret_len);
|
||||
addr[0] = secret;
|
||||
elen[0] = secret_len;
|
||||
if (first) {
|
||||
MD5Update(&context, req_authenticator, MD5_MAC_LEN);
|
||||
MD5Update(&context, key, 2); /* Salt */
|
||||
first = 0;
|
||||
} else
|
||||
MD5Update(&context, pos - MD5_MAC_LEN, MD5_MAC_LEN);
|
||||
MD5Final(hash, &context);
|
||||
addr[1] = req_authenticator;
|
||||
elen[1] = MD5_MAC_LEN;
|
||||
addr[2] = key;
|
||||
elen[2] = 2; /* Salt */
|
||||
} else {
|
||||
addr[1] = pos - MD5_MAC_LEN;
|
||||
elen[1] = MD5_MAC_LEN;
|
||||
}
|
||||
md5_vector(first ? 3 : 2, addr, elen, hash);
|
||||
first = 0;
|
||||
|
||||
for (i = 0; i < MD5_MAC_LEN; i++)
|
||||
*ppos++ = *pos++ ^ hash[i];
|
||||
@ -845,7 +857,8 @@ static void encrypt_ms_key(const u8 *key, size_t key_len, u16 salt,
|
||||
{
|
||||
int i, len, first = 1;
|
||||
u8 hash[MD5_MAC_LEN], saltbuf[2], *pos;
|
||||
MD5_CTX context;
|
||||
const u8 *addr[3];
|
||||
size_t _len[3];
|
||||
|
||||
saltbuf[0] = salt >> 8;
|
||||
saltbuf[1] = salt;
|
||||
@ -864,16 +877,19 @@ static void encrypt_ms_key(const u8 *key, size_t key_len, u16 salt,
|
||||
while (len > 0) {
|
||||
/* b(1) = MD5(Secret + Request-Authenticator + Salt)
|
||||
* b(i) = MD5(Secret + c(i - 1)) for i > 1 */
|
||||
MD5Init(&context);
|
||||
MD5Update(&context, secret, secret_len);
|
||||
addr[0] = secret;
|
||||
_len[0] = secret_len;
|
||||
if (first) {
|
||||
MD5Update(&context, req_authenticator, MD5_MAC_LEN);
|
||||
MD5Update(&context, saltbuf, sizeof(saltbuf));
|
||||
first = 0;
|
||||
addr[1] = req_authenticator;
|
||||
_len[1] = MD5_MAC_LEN;
|
||||
addr[2] = saltbuf;
|
||||
_len[2] = sizeof(saltbuf);
|
||||
} else {
|
||||
MD5Update(&context, pos - MD5_MAC_LEN, MD5_MAC_LEN);
|
||||
addr[1] = pos - MD5_MAC_LEN;
|
||||
_len[1] = MD5_MAC_LEN;
|
||||
}
|
||||
MD5Final(hash, &context);
|
||||
md5_vector(first ? 3 : 2, addr, _len, hash);
|
||||
first = 0;
|
||||
|
||||
for (i = 0; i < MD5_MAC_LEN; i++)
|
||||
*pos++ ^= hash[i];
|
||||
@ -1037,8 +1053,9 @@ radius_msg_add_attr_user_password(struct radius_msg *msg,
|
||||
{
|
||||
u8 buf[128];
|
||||
int padlen, i, pos;
|
||||
MD5_CTX context;
|
||||
size_t buf_len;
|
||||
const u8 *addr[2];
|
||||
size_t len[2];
|
||||
u8 hash[16];
|
||||
|
||||
if (data_len > 128)
|
||||
@ -1054,20 +1071,22 @@ radius_msg_add_attr_user_password(struct radius_msg *msg,
|
||||
buf_len += padlen;
|
||||
}
|
||||
|
||||
MD5Init(&context);
|
||||
MD5Update(&context, secret, secret_len);
|
||||
MD5Update(&context, msg->hdr->authenticator, 16);
|
||||
MD5Final(hash, &context);
|
||||
addr[0] = secret;
|
||||
len[0] = secret_len;
|
||||
addr[1] = msg->hdr->authenticator;
|
||||
len[1] = 16;
|
||||
md5_vector(2, addr, len, hash);
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
buf[i] ^= hash[i];
|
||||
pos = 16;
|
||||
|
||||
while (pos < buf_len) {
|
||||
MD5Init(&context);
|
||||
MD5Update(&context, secret, secret_len);
|
||||
MD5Update(&context, &buf[pos - 16], 16);
|
||||
MD5Final(hash, &context);
|
||||
addr[0] = secret;
|
||||
len[0] = secret_len;
|
||||
addr[1] = &buf[pos - 16];
|
||||
len[1] = 16;
|
||||
md5_vector(2, addr, len, hash);
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
buf[pos + i] ^= hash[i];
|
||||
@ -1104,13 +1123,14 @@ int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len)
|
||||
|
||||
|
||||
int radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf,
|
||||
size_t *len)
|
||||
size_t *len, const u8 *start)
|
||||
{
|
||||
int i;
|
||||
struct radius_attr_hdr *attr = NULL;
|
||||
|
||||
for (i = 0; i < msg->attr_used; i++) {
|
||||
if (msg->attrs[i]->type == type) {
|
||||
if (msg->attrs[i]->type == type &&
|
||||
(start == NULL || (u8 *) msg->attrs[i] > start)) {
|
||||
attr = msg->attrs[i];
|
||||
break;
|
||||
}
|
||||
@ -1123,3 +1143,18 @@ int radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf,
|
||||
*len = attr->length - sizeof(*attr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int radius_msg_count_attr(struct radius_msg *msg, u8 type, int min_len)
|
||||
{
|
||||
int i, count;
|
||||
|
||||
for (count = 0, i = 0; i < msg->attr_used; i++) {
|
||||
if (msg->attrs[i]->type == type &&
|
||||
msg->attrs[i]->length >=
|
||||
sizeof(struct radius_attr_hdr) + min_len)
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
@ -63,7 +63,8 @@ enum { RADIUS_ATTR_USER_NAME = 1,
|
||||
RADIUS_ATTR_CONNECT_INFO = 77,
|
||||
RADIUS_ATTR_EAP_MESSAGE = 79,
|
||||
RADIUS_ATTR_MESSAGE_AUTHENTICATOR = 80,
|
||||
RADIUS_ATTR_ACCT_INTERIM_INTERVAL = 85
|
||||
RADIUS_ATTR_ACCT_INTERIM_INTERVAL = 85,
|
||||
RADIUS_ATTR_NAS_IPV6_ADDRESS = 95
|
||||
};
|
||||
|
||||
|
||||
@ -168,16 +169,16 @@ int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret,
|
||||
void radius_msg_finish_acct(struct radius_msg *msg, u8 *secret,
|
||||
size_t secret_len);
|
||||
struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type,
|
||||
u8 *data, size_t data_len);
|
||||
const u8 *data, size_t data_len);
|
||||
struct radius_msg *radius_msg_parse(const u8 *data, size_t len);
|
||||
int radius_msg_add_eap(struct radius_msg *msg, u8 *data, size_t data_len);
|
||||
int radius_msg_add_eap(struct radius_msg *msg, const u8 *data,
|
||||
size_t data_len);
|
||||
u8 *radius_msg_get_eap(struct radius_msg *msg, size_t *len);
|
||||
int radius_msg_verify(struct radius_msg *msg, u8 *secret, size_t secret_len,
|
||||
struct radius_msg *sent_msg);
|
||||
int radius_msg_verify(struct radius_msg *msg, const u8 *secret,
|
||||
size_t secret_len, struct radius_msg *sent_msg,
|
||||
int auth);
|
||||
int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret,
|
||||
size_t secret_len, const u8 *req_auth);
|
||||
int radius_msg_verify_acct(struct radius_msg *msg, u8 *secret,
|
||||
size_t secret_len, struct radius_msg *sent_msg);
|
||||
int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src,
|
||||
u8 type);
|
||||
void radius_msg_make_authenticator(struct radius_msg *msg,
|
||||
@ -219,6 +220,7 @@ static inline int radius_msg_get_attr_int32(struct radius_msg *msg, u8 type,
|
||||
return 0;
|
||||
}
|
||||
int radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf,
|
||||
size_t *len);
|
||||
size_t *len, const u8 *start);
|
||||
int radius_msg_count_attr(struct radius_msg *msg, u8 type, int min_len);
|
||||
|
||||
#endif /* RADIUS_H */
|
||||
|
@ -16,14 +16,16 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <errno.h>
|
||||
#ifndef CONFIG_NATIVE_WINDOWS
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#endif /* CONFIG_NATIVE_WINDOWS */
|
||||
|
||||
#include "hostapd.h"
|
||||
#include "radius.h"
|
||||
@ -74,10 +76,15 @@ struct radius_msg_list {
|
||||
|
||||
|
||||
struct radius_client_data {
|
||||
struct hostapd_data *hapd;
|
||||
void *ctx;
|
||||
struct hostapd_radius_servers *conf;
|
||||
|
||||
int auth_serv_sock; /* socket for authentication RADIUS messages */
|
||||
int acct_serv_sock; /* socket for accounting RADIUS messages */
|
||||
int auth_serv_sock6;
|
||||
int acct_serv_sock6;
|
||||
int auth_sock; /* currently used socket */
|
||||
int acct_sock; /* currently used socket */
|
||||
|
||||
struct radius_rx_handler *auth_handlers;
|
||||
size_t num_auth_handlers;
|
||||
@ -95,7 +102,7 @@ static int
|
||||
radius_change_server(struct radius_client_data *radius,
|
||||
struct hostapd_radius_server *nserv,
|
||||
struct hostapd_radius_server *oserv,
|
||||
int sock, int auth);
|
||||
int sock, int sock6, int auth);
|
||||
static int radius_client_init_acct(struct radius_client_data *radius);
|
||||
static int radius_client_init_auth(struct radius_client_data *radius);
|
||||
|
||||
@ -146,11 +153,11 @@ int radius_client_register(struct radius_client_data *radius,
|
||||
static void radius_client_handle_send_error(struct radius_client_data *radius,
|
||||
int s, RadiusType msg_type)
|
||||
{
|
||||
struct hostapd_data *hapd = radius->hapd;
|
||||
#ifndef CONFIG_NATIVE_WINDOWS
|
||||
int _errno = errno;
|
||||
perror("send[RADIUS]");
|
||||
if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL) {
|
||||
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_RADIUS,
|
||||
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
|
||||
HOSTAPD_LEVEL_INFO,
|
||||
"Send failed - maybe interface status changed -"
|
||||
" try to connect again");
|
||||
@ -161,38 +168,40 @@ static void radius_client_handle_send_error(struct radius_client_data *radius,
|
||||
else
|
||||
radius_client_init_auth(radius);
|
||||
}
|
||||
#endif /* CONFIG_NATIVE_WINDOWS */
|
||||
}
|
||||
|
||||
|
||||
static int radius_client_retransmit(struct radius_client_data *radius,
|
||||
struct radius_msg_list *entry, time_t now)
|
||||
{
|
||||
struct hostapd_data *hapd = radius->hapd;
|
||||
struct hostapd_radius_servers *conf = radius->conf;
|
||||
int s;
|
||||
|
||||
if (entry->msg_type == RADIUS_ACCT ||
|
||||
entry->msg_type == RADIUS_ACCT_INTERIM) {
|
||||
s = radius->acct_serv_sock;
|
||||
s = radius->acct_sock;
|
||||
if (entry->attempts == 0)
|
||||
hapd->conf->acct_server->requests++;
|
||||
conf->acct_server->requests++;
|
||||
else {
|
||||
hapd->conf->acct_server->timeouts++;
|
||||
hapd->conf->acct_server->retransmissions++;
|
||||
conf->acct_server->timeouts++;
|
||||
conf->acct_server->retransmissions++;
|
||||
}
|
||||
} else {
|
||||
s = radius->auth_serv_sock;
|
||||
s = radius->auth_sock;
|
||||
if (entry->attempts == 0)
|
||||
hapd->conf->auth_server->requests++;
|
||||
conf->auth_server->requests++;
|
||||
else {
|
||||
hapd->conf->auth_server->timeouts++;
|
||||
hapd->conf->auth_server->retransmissions++;
|
||||
conf->auth_server->timeouts++;
|
||||
conf->auth_server->retransmissions++;
|
||||
}
|
||||
}
|
||||
|
||||
/* retransmit; remove entry if too many attempts */
|
||||
entry->attempts++;
|
||||
HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Resending RADIUS message (id=%d)"
|
||||
"\n", entry->msg->hdr->identifier);
|
||||
hostapd_logger(radius->ctx, entry->addr, HOSTAPD_MODULE_RADIUS,
|
||||
HOSTAPD_LEVEL_DEBUG, "Resending RADIUS message (id=%d)",
|
||||
entry->msg->hdr->identifier);
|
||||
|
||||
gettimeofday(&entry->last_attempt, NULL);
|
||||
if (send(s, entry->msg->buf, entry->msg->buf_used, 0) < 0)
|
||||
@ -215,10 +224,11 @@ static int radius_client_retransmit(struct radius_client_data *radius,
|
||||
static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
struct radius_client_data *radius = eloop_ctx;
|
||||
struct hostapd_data *hapd = radius->hapd;
|
||||
struct hostapd_radius_servers *conf = radius->conf;
|
||||
time_t now, first;
|
||||
struct radius_msg_list *entry, *prev, *tmp;
|
||||
int auth_failover = 0, acct_failover = 0;
|
||||
char abuf[50];
|
||||
|
||||
entry = radius->msgs;
|
||||
if (!entry)
|
||||
@ -263,20 +273,21 @@ static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
|
||||
first = now;
|
||||
eloop_register_timeout(first - now, 0,
|
||||
radius_client_timer, radius, NULL);
|
||||
HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Next RADIUS client "
|
||||
"retransmit in %ld seconds\n",
|
||||
(long int) (first - now));
|
||||
|
||||
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
|
||||
HOSTAPD_LEVEL_DEBUG, "Next RADIUS client "
|
||||
"retransmit in %ld seconds",
|
||||
(long int) (first - now));
|
||||
}
|
||||
|
||||
if (auth_failover && hapd->conf->num_auth_servers > 1) {
|
||||
if (auth_failover && conf->num_auth_servers > 1) {
|
||||
struct hostapd_radius_server *next, *old;
|
||||
old = hapd->conf->auth_server;
|
||||
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_RADIUS,
|
||||
old = conf->auth_server;
|
||||
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
|
||||
HOSTAPD_LEVEL_NOTICE,
|
||||
"No response from Authentication server "
|
||||
"%s:%d - failover",
|
||||
inet_ntoa(old->addr), old->port);
|
||||
hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
|
||||
old->port);
|
||||
|
||||
for (entry = radius->msgs; entry; entry = entry->next) {
|
||||
if (entry->msg_type == RADIUS_AUTH)
|
||||
@ -284,22 +295,23 @@ static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
|
||||
}
|
||||
|
||||
next = old + 1;
|
||||
if (next > &(hapd->conf->auth_servers
|
||||
[hapd->conf->num_auth_servers - 1]))
|
||||
next = hapd->conf->auth_servers;
|
||||
hapd->conf->auth_server = next;
|
||||
if (next > &(conf->auth_servers[conf->num_auth_servers - 1]))
|
||||
next = conf->auth_servers;
|
||||
conf->auth_server = next;
|
||||
radius_change_server(radius, next, old,
|
||||
radius->auth_serv_sock, 1);
|
||||
radius->auth_serv_sock,
|
||||
radius->auth_serv_sock6, 1);
|
||||
}
|
||||
|
||||
if (acct_failover && hapd->conf->num_acct_servers > 1) {
|
||||
if (acct_failover && conf->num_acct_servers > 1) {
|
||||
struct hostapd_radius_server *next, *old;
|
||||
old = hapd->conf->acct_server;
|
||||
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_RADIUS,
|
||||
old = conf->acct_server;
|
||||
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
|
||||
HOSTAPD_LEVEL_NOTICE,
|
||||
"No response from Accounting server "
|
||||
"%s:%d - failover",
|
||||
inet_ntoa(old->addr), old->port);
|
||||
hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
|
||||
old->port);
|
||||
|
||||
for (entry = radius->msgs; entry; entry = entry->next) {
|
||||
if (entry->msg_type == RADIUS_ACCT ||
|
||||
@ -308,19 +320,18 @@ static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
|
||||
}
|
||||
|
||||
next = old + 1;
|
||||
if (next > &hapd->conf->acct_servers
|
||||
[hapd->conf->num_acct_servers - 1])
|
||||
next = hapd->conf->acct_servers;
|
||||
hapd->conf->acct_server = next;
|
||||
if (next > &conf->acct_servers[conf->num_acct_servers - 1])
|
||||
next = conf->acct_servers;
|
||||
conf->acct_server = next;
|
||||
radius_change_server(radius, next, old,
|
||||
radius->acct_serv_sock, 0);
|
||||
radius->acct_serv_sock,
|
||||
radius->acct_serv_sock6, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void radius_client_update_timeout(struct radius_client_data *radius)
|
||||
{
|
||||
struct hostapd_data *hapd = radius->hapd;
|
||||
time_t now, first;
|
||||
struct radius_msg_list *entry;
|
||||
|
||||
@ -341,8 +352,9 @@ static void radius_client_update_timeout(struct radius_client_data *radius)
|
||||
first = now;
|
||||
eloop_register_timeout(first - now, 0, radius_client_timer, radius,
|
||||
NULL);
|
||||
HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Next RADIUS client retransmit in"
|
||||
" %ld seconds\n", (long int) (first - now));
|
||||
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
|
||||
HOSTAPD_LEVEL_DEBUG, "Next RADIUS client retransmit in"
|
||||
" %ld seconds\n", (long int) (first - now));
|
||||
}
|
||||
|
||||
|
||||
@ -405,7 +417,6 @@ static void radius_client_list_add(struct radius_client_data *radius,
|
||||
static void radius_client_list_del(struct radius_client_data *radius,
|
||||
RadiusType msg_type, u8 *addr)
|
||||
{
|
||||
struct hostapd_data *hapd = radius->hapd;
|
||||
struct radius_msg_list *entry, *prev, *tmp;
|
||||
|
||||
if (addr == NULL)
|
||||
@ -422,9 +433,10 @@ static void radius_client_list_del(struct radius_client_data *radius,
|
||||
radius->msgs = entry->next;
|
||||
tmp = entry;
|
||||
entry = entry->next;
|
||||
HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
|
||||
"Removing matching RADIUS message for "
|
||||
MACSTR "\n", MAC2STR(addr));
|
||||
hostapd_logger(radius->ctx, addr,
|
||||
HOSTAPD_MODULE_RADIUS,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"Removing matching RADIUS message");
|
||||
radius_client_msg_free(tmp);
|
||||
radius->num_msgs--;
|
||||
continue;
|
||||
@ -438,7 +450,7 @@ static void radius_client_list_del(struct radius_client_data *radius,
|
||||
int radius_client_send(struct radius_client_data *radius,
|
||||
struct radius_msg *msg, RadiusType msg_type, u8 *addr)
|
||||
{
|
||||
struct hostapd_data *hapd = radius->hapd;
|
||||
struct hostapd_radius_servers *conf = radius->conf;
|
||||
u8 *shared_secret;
|
||||
size_t shared_secret_len;
|
||||
char *name;
|
||||
@ -450,24 +462,25 @@ int radius_client_send(struct radius_client_data *radius,
|
||||
}
|
||||
|
||||
if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) {
|
||||
shared_secret = hapd->conf->acct_server->shared_secret;
|
||||
shared_secret_len = hapd->conf->acct_server->shared_secret_len;
|
||||
shared_secret = conf->acct_server->shared_secret;
|
||||
shared_secret_len = conf->acct_server->shared_secret_len;
|
||||
radius_msg_finish_acct(msg, shared_secret, shared_secret_len);
|
||||
name = "accounting";
|
||||
s = radius->acct_serv_sock;
|
||||
hapd->conf->acct_server->requests++;
|
||||
s = radius->acct_sock;
|
||||
conf->acct_server->requests++;
|
||||
} else {
|
||||
shared_secret = hapd->conf->auth_server->shared_secret;
|
||||
shared_secret_len = hapd->conf->auth_server->shared_secret_len;
|
||||
shared_secret = conf->auth_server->shared_secret;
|
||||
shared_secret_len = conf->auth_server->shared_secret_len;
|
||||
radius_msg_finish(msg, shared_secret, shared_secret_len);
|
||||
name = "authentication";
|
||||
s = radius->auth_serv_sock;
|
||||
hapd->conf->auth_server->requests++;
|
||||
s = radius->auth_sock;
|
||||
conf->auth_server->requests++;
|
||||
}
|
||||
|
||||
HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
|
||||
"Sending RADIUS message to %s server\n", name);
|
||||
if (HOSTAPD_DEBUG_COND(HOSTAPD_DEBUG_MSGDUMPS))
|
||||
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
|
||||
HOSTAPD_LEVEL_DEBUG, "Sending RADIUS message to %s "
|
||||
"server", name);
|
||||
if (conf->msg_dumps)
|
||||
radius_msg_dump(msg);
|
||||
|
||||
res = send(s, msg->buf, msg->buf_used, 0);
|
||||
@ -484,7 +497,7 @@ int radius_client_send(struct radius_client_data *radius,
|
||||
static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
|
||||
{
|
||||
struct radius_client_data *radius = eloop_ctx;
|
||||
struct hostapd_data *hapd = radius->hapd;
|
||||
struct hostapd_radius_servers *conf = radius->conf;
|
||||
RadiusType msg_type = (RadiusType) sock_ctx;
|
||||
int len, i, roundtrip;
|
||||
unsigned char buf[3000];
|
||||
@ -499,11 +512,11 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
|
||||
if (msg_type == RADIUS_ACCT) {
|
||||
handlers = radius->acct_handlers;
|
||||
num_handlers = radius->num_acct_handlers;
|
||||
rconf = hapd->conf->acct_server;
|
||||
rconf = conf->acct_server;
|
||||
} else {
|
||||
handlers = radius->auth_handlers;
|
||||
num_handlers = radius->num_auth_handlers;
|
||||
rconf = hapd->conf->auth_server;
|
||||
rconf = conf->auth_server;
|
||||
}
|
||||
|
||||
len = recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
|
||||
@ -511,8 +524,9 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
|
||||
perror("recv[RADIUS]");
|
||||
return;
|
||||
}
|
||||
HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
|
||||
"Received %d bytes from RADIUS server\n", len);
|
||||
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
|
||||
HOSTAPD_LEVEL_DEBUG, "Received %d bytes from RADIUS "
|
||||
"server", len);
|
||||
if (len == sizeof(buf)) {
|
||||
printf("Possibly too long UDP frame for our buffer - "
|
||||
"dropping it\n");
|
||||
@ -526,9 +540,9 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
|
||||
return;
|
||||
}
|
||||
|
||||
HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
|
||||
"Received RADIUS message\n");
|
||||
if (HOSTAPD_DEBUG_COND(HOSTAPD_DEBUG_MSGDUMPS))
|
||||
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
|
||||
HOSTAPD_LEVEL_DEBUG, "Received RADIUS message");
|
||||
if (conf->msg_dumps)
|
||||
radius_msg_dump(msg);
|
||||
|
||||
switch (msg->hdr->code) {
|
||||
@ -562,19 +576,22 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
|
||||
}
|
||||
|
||||
if (req == NULL) {
|
||||
HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
|
||||
"No matching RADIUS request found (type=%d "
|
||||
"id=%d) - dropping packet\n",
|
||||
msg_type, msg->hdr->identifier);
|
||||
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"No matching RADIUS request found (type=%d "
|
||||
"id=%d) - dropping packet",
|
||||
msg_type, msg->hdr->identifier);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
roundtrip = (tv.tv_sec - req->last_attempt.tv_sec) * 100 +
|
||||
(tv.tv_usec - req->last_attempt.tv_usec) / 10000;
|
||||
HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Received RADIUS packet matched "
|
||||
"with a pending request, round trip time %d.%02d sec\n",
|
||||
roundtrip / 100, roundtrip % 100);
|
||||
hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"Received RADIUS packet matched with a pending "
|
||||
"request, round trip time %d.%02d sec",
|
||||
roundtrip / 100, roundtrip % 100);
|
||||
rconf->round_trip_time = roundtrip;
|
||||
|
||||
/* Remove ACKed RADIUS packet from retransmit list */
|
||||
@ -610,7 +627,7 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
|
||||
rconf->bad_authenticators++;
|
||||
else
|
||||
rconf->unknown_types++;
|
||||
hostapd_logger(hapd, req->addr, HOSTAPD_MODULE_RADIUS,
|
||||
hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS,
|
||||
HOSTAPD_LEVEL_DEBUG, "No RADIUS RX handler found "
|
||||
"(type=%d code=%d id=%d)%s - dropping packet",
|
||||
msg_type, msg->hdr->code, msg->hdr->identifier,
|
||||
@ -626,7 +643,6 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
|
||||
|
||||
u8 radius_client_get_id(struct radius_client_data *radius)
|
||||
{
|
||||
struct hostapd_data *hapd = radius->hapd;
|
||||
struct radius_msg_list *entry, *prev, *remove;
|
||||
u8 id = radius->next_radius_identifier++;
|
||||
|
||||
@ -636,9 +652,11 @@ u8 radius_client_get_id(struct radius_client_data *radius)
|
||||
prev = NULL;
|
||||
while (entry) {
|
||||
if (entry->msg->hdr->identifier == id) {
|
||||
HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
|
||||
"Removing pending RADIUS message, since "
|
||||
"its id (%d) is reused\n", id);
|
||||
hostapd_logger(radius->ctx, entry->addr,
|
||||
HOSTAPD_MODULE_RADIUS,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"Removing pending RADIUS message, "
|
||||
"since its id (%d) is reused", id);
|
||||
if (prev)
|
||||
prev->next = entry->next;
|
||||
else
|
||||
@ -681,15 +699,23 @@ static int
|
||||
radius_change_server(struct radius_client_data *radius,
|
||||
struct hostapd_radius_server *nserv,
|
||||
struct hostapd_radius_server *oserv,
|
||||
int sock, int auth)
|
||||
int sock, int sock6, int auth)
|
||||
{
|
||||
struct hostapd_data *hapd = radius->hapd;
|
||||
struct sockaddr_in serv;
|
||||
#ifdef CONFIG_IPV6
|
||||
struct sockaddr_in6 serv6;
|
||||
#endif /* CONFIG_IPV6 */
|
||||
struct sockaddr *addr;
|
||||
socklen_t addrlen;
|
||||
char abuf[50];
|
||||
int sel_sock;
|
||||
|
||||
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_RADIUS, HOSTAPD_LEVEL_INFO,
|
||||
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
|
||||
HOSTAPD_LEVEL_INFO,
|
||||
"%s server %s:%d",
|
||||
auth ? "Authentication" : "Accounting",
|
||||
inet_ntoa(nserv->addr), nserv->port);
|
||||
hostapd_ip_txt(&nserv->addr, abuf, sizeof(abuf)),
|
||||
nserv->port);
|
||||
|
||||
if (!oserv || nserv->shared_secret_len != oserv->shared_secret_len ||
|
||||
memcmp(nserv->shared_secret, oserv->shared_secret,
|
||||
@ -720,16 +746,42 @@ radius_change_server(struct radius_client_data *radius,
|
||||
}
|
||||
}
|
||||
|
||||
memset(&serv, 0, sizeof(serv));
|
||||
serv.sin_family = AF_INET;
|
||||
serv.sin_addr.s_addr = nserv->addr.s_addr;
|
||||
serv.sin_port = htons(nserv->port);
|
||||
switch (nserv->addr.af) {
|
||||
case AF_INET:
|
||||
memset(&serv, 0, sizeof(serv));
|
||||
serv.sin_family = AF_INET;
|
||||
serv.sin_addr.s_addr = nserv->addr.u.v4.s_addr;
|
||||
serv.sin_port = htons(nserv->port);
|
||||
addr = (struct sockaddr *) &serv;
|
||||
addrlen = sizeof(serv);
|
||||
sel_sock = sock;
|
||||
break;
|
||||
#ifdef CONFIG_IPV6
|
||||
case AF_INET6:
|
||||
memset(&serv6, 0, sizeof(serv6));
|
||||
serv6.sin6_family = AF_INET6;
|
||||
memcpy(&serv6.sin6_addr, &nserv->addr.u.v6,
|
||||
sizeof(struct in6_addr));
|
||||
serv6.sin6_port = htons(nserv->port);
|
||||
addr = (struct sockaddr *) &serv6;
|
||||
addrlen = sizeof(serv6);
|
||||
sel_sock = sock6;
|
||||
break;
|
||||
#endif /* CONFIG_IPV6 */
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (connect(sock, (struct sockaddr *) &serv, sizeof(serv)) < 0) {
|
||||
if (connect(sel_sock, addr, addrlen) < 0) {
|
||||
perror("connect[radius]");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (auth)
|
||||
radius->auth_sock = sel_sock;
|
||||
else
|
||||
radius->acct_sock = sel_sock;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -737,28 +789,29 @@ radius_change_server(struct radius_client_data *radius,
|
||||
static void radius_retry_primary_timer(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
struct radius_client_data *radius = eloop_ctx;
|
||||
struct hostapd_data *hapd = radius->hapd;
|
||||
struct hostapd_radius_servers *conf = radius->conf;
|
||||
struct hostapd_radius_server *oserv;
|
||||
|
||||
if (radius->auth_serv_sock >= 0 && hapd->conf->auth_servers &&
|
||||
hapd->conf->auth_server != hapd->conf->auth_servers) {
|
||||
oserv = hapd->conf->auth_server;
|
||||
hapd->conf->auth_server = hapd->conf->auth_servers;
|
||||
radius_change_server(radius, hapd->conf->auth_server, oserv,
|
||||
radius->auth_serv_sock, 1);
|
||||
if (radius->auth_sock >= 0 && conf->auth_servers &&
|
||||
conf->auth_server != conf->auth_servers) {
|
||||
oserv = conf->auth_server;
|
||||
conf->auth_server = conf->auth_servers;
|
||||
radius_change_server(radius, conf->auth_server, oserv,
|
||||
radius->auth_serv_sock,
|
||||
radius->auth_serv_sock6, 1);
|
||||
}
|
||||
|
||||
if (radius->acct_serv_sock >= 0 && hapd->conf->acct_servers &&
|
||||
hapd->conf->acct_server != hapd->conf->acct_servers) {
|
||||
oserv = hapd->conf->acct_server;
|
||||
hapd->conf->acct_server = hapd->conf->acct_servers;
|
||||
radius_change_server(radius, hapd->conf->acct_server, oserv,
|
||||
radius->acct_serv_sock, 0);
|
||||
if (radius->acct_sock >= 0 && conf->acct_servers &&
|
||||
conf->acct_server != conf->acct_servers) {
|
||||
oserv = conf->acct_server;
|
||||
conf->acct_server = conf->acct_servers;
|
||||
radius_change_server(radius, conf->acct_server, oserv,
|
||||
radius->acct_serv_sock,
|
||||
radius->acct_serv_sock6, 0);
|
||||
}
|
||||
|
||||
if (hapd->conf->radius_retry_primary_interval)
|
||||
eloop_register_timeout(hapd->conf->
|
||||
radius_retry_primary_interval, 0,
|
||||
if (conf->retry_primary_interval)
|
||||
eloop_register_timeout(conf->retry_primary_interval, 0,
|
||||
radius_retry_primary_timer, radius,
|
||||
NULL);
|
||||
}
|
||||
@ -766,17 +819,32 @@ static void radius_retry_primary_timer(void *eloop_ctx, void *timeout_ctx)
|
||||
|
||||
static int radius_client_init_auth(struct radius_client_data *radius)
|
||||
{
|
||||
struct hostapd_data *hapd = radius->hapd;
|
||||
struct hostapd_radius_servers *conf = radius->conf;
|
||||
int ok = 0;
|
||||
|
||||
radius->auth_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (radius->auth_serv_sock < 0) {
|
||||
if (radius->auth_serv_sock < 0)
|
||||
perror("socket[PF_INET,SOCK_DGRAM]");
|
||||
else
|
||||
ok++;
|
||||
|
||||
#ifdef CONFIG_IPV6
|
||||
radius->auth_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
|
||||
if (radius->auth_serv_sock6 < 0)
|
||||
perror("socket[PF_INET6,SOCK_DGRAM]");
|
||||
else
|
||||
ok++;
|
||||
#endif /* CONFIG_IPV6 */
|
||||
|
||||
if (ok == 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
radius_change_server(radius, hapd->conf->auth_server, NULL,
|
||||
radius->auth_serv_sock, 1);
|
||||
radius_change_server(radius, conf->auth_server, NULL,
|
||||
radius->auth_serv_sock, radius->auth_serv_sock6,
|
||||
1);
|
||||
|
||||
if (eloop_register_read_sock(radius->auth_serv_sock,
|
||||
if (radius->auth_serv_sock >= 0 &&
|
||||
eloop_register_read_sock(radius->auth_serv_sock,
|
||||
radius_client_receive, radius,
|
||||
(void *) RADIUS_AUTH)) {
|
||||
printf("Could not register read socket for authentication "
|
||||
@ -784,23 +852,38 @@ static int radius_client_init_auth(struct radius_client_data *radius)
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IPV6
|
||||
if (radius->auth_serv_sock6 >= 0 &&
|
||||
eloop_register_read_sock(radius->auth_serv_sock6,
|
||||
radius_client_receive, radius,
|
||||
(void *) RADIUS_AUTH)) {
|
||||
printf("Could not register read socket for authentication "
|
||||
"server\n");
|
||||
return -1;
|
||||
}
|
||||
#endif /* CONFIG_IPV6 */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int radius_client_init_acct(struct radius_client_data *radius)
|
||||
{
|
||||
struct hostapd_data *hapd = radius->hapd;
|
||||
struct hostapd_radius_servers *conf = radius->conf;
|
||||
int ok = 0;
|
||||
|
||||
radius->acct_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (radius->acct_serv_sock < 0) {
|
||||
if (radius->acct_serv_sock < 0)
|
||||
perror("socket[PF_INET,SOCK_DGRAM]");
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
ok++;
|
||||
|
||||
radius_change_server(radius, hapd->conf->acct_server, NULL,
|
||||
radius->acct_serv_sock, 0);
|
||||
radius_change_server(radius, conf->acct_server, NULL,
|
||||
radius->acct_serv_sock, radius->acct_serv_sock6,
|
||||
0);
|
||||
|
||||
if (eloop_register_read_sock(radius->acct_serv_sock,
|
||||
if (radius->acct_serv_sock >= 0 &&
|
||||
eloop_register_read_sock(radius->acct_serv_sock,
|
||||
radius_client_receive, radius,
|
||||
(void *) RADIUS_ACCT)) {
|
||||
printf("Could not register read socket for accounting "
|
||||
@ -808,11 +891,23 @@ static int radius_client_init_acct(struct radius_client_data *radius)
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IPV6
|
||||
if (radius->acct_serv_sock6 >= 0 &&
|
||||
eloop_register_read_sock(radius->acct_serv_sock6,
|
||||
radius_client_receive, radius,
|
||||
(void *) RADIUS_ACCT)) {
|
||||
printf("Could not register read socket for accounting "
|
||||
"server\n");
|
||||
return -1;
|
||||
}
|
||||
#endif /* CONFIG_IPV6 */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct radius_client_data * radius_client_init(struct hostapd_data *hapd)
|
||||
struct radius_client_data *
|
||||
radius_client_init(void *ctx, struct hostapd_radius_servers *conf)
|
||||
{
|
||||
struct radius_client_data *radius;
|
||||
|
||||
@ -821,22 +916,24 @@ struct radius_client_data * radius_client_init(struct hostapd_data *hapd)
|
||||
return NULL;
|
||||
|
||||
memset(radius, 0, sizeof(struct radius_client_data));
|
||||
radius->hapd = hapd;
|
||||
radius->auth_serv_sock = radius->acct_serv_sock = -1;
|
||||
radius->ctx = ctx;
|
||||
radius->conf = conf;
|
||||
radius->auth_serv_sock = radius->acct_serv_sock =
|
||||
radius->auth_serv_sock6 = radius->acct_serv_sock6 =
|
||||
radius->auth_sock = radius->acct_sock = -1;
|
||||
|
||||
if (hapd->conf->auth_server && radius_client_init_auth(radius)) {
|
||||
if (conf->auth_server && radius_client_init_auth(radius)) {
|
||||
radius_client_deinit(radius);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (hapd->conf->acct_server && radius_client_init_acct(radius)) {
|
||||
if (conf->acct_server && radius_client_init_acct(radius)) {
|
||||
radius_client_deinit(radius);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (hapd->conf->radius_retry_primary_interval)
|
||||
eloop_register_timeout(hapd->conf->
|
||||
radius_retry_primary_interval, 0,
|
||||
if (conf->retry_primary_interval)
|
||||
eloop_register_timeout(conf->retry_primary_interval, 0,
|
||||
radius_retry_primary_timer, radius,
|
||||
NULL);
|
||||
|
||||
@ -860,7 +957,6 @@ void radius_client_deinit(struct radius_client_data *radius)
|
||||
|
||||
void radius_client_flush_auth(struct radius_client_data *radius, u8 *addr)
|
||||
{
|
||||
struct hostapd_data *hapd = radius->hapd;
|
||||
struct radius_msg_list *entry, *prev, *tmp;
|
||||
|
||||
prev = NULL;
|
||||
@ -868,7 +964,8 @@ void radius_client_flush_auth(struct radius_client_data *radius, u8 *addr)
|
||||
while (entry) {
|
||||
if (entry->msg_type == RADIUS_AUTH &&
|
||||
memcmp(entry->addr, addr, ETH_ALEN) == 0) {
|
||||
hostapd_logger(hapd, addr, HOSTAPD_MODULE_RADIUS,
|
||||
hostapd_logger(radius->ctx, addr,
|
||||
HOSTAPD_MODULE_RADIUS,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"Removing pending RADIUS authentication"
|
||||
" message for removed client");
|
||||
@ -897,6 +994,7 @@ static int radius_client_dump_auth_server(char *buf, size_t buflen,
|
||||
{
|
||||
int pending = 0;
|
||||
struct radius_msg_list *msg;
|
||||
char abuf[50];
|
||||
|
||||
if (cli) {
|
||||
for (msg = cli->msgs; msg; msg = msg->next) {
|
||||
@ -922,7 +1020,7 @@ static int radius_client_dump_auth_server(char *buf, size_t buflen,
|
||||
"radiusAuthClientUnknownTypes=%u\n"
|
||||
"radiusAuthClientPacketsDropped=%u\n",
|
||||
serv->index,
|
||||
inet_ntoa(serv->addr),
|
||||
hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
|
||||
serv->port,
|
||||
serv->round_trip_time,
|
||||
serv->requests,
|
||||
@ -945,6 +1043,7 @@ static int radius_client_dump_acct_server(char *buf, size_t buflen,
|
||||
{
|
||||
int pending = 0;
|
||||
struct radius_msg_list *msg;
|
||||
char abuf[50];
|
||||
|
||||
if (cli) {
|
||||
for (msg = cli->msgs; msg; msg = msg->next) {
|
||||
@ -969,7 +1068,7 @@ static int radius_client_dump_acct_server(char *buf, size_t buflen,
|
||||
"radiusAccClientUnknownTypes=%u\n"
|
||||
"radiusAccClientPacketsDropped=%u\n",
|
||||
serv->index,
|
||||
inet_ntoa(serv->addr),
|
||||
hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
|
||||
serv->port,
|
||||
serv->round_trip_time,
|
||||
serv->requests,
|
||||
@ -987,27 +1086,27 @@ static int radius_client_dump_acct_server(char *buf, size_t buflen,
|
||||
int radius_client_get_mib(struct radius_client_data *radius, char *buf,
|
||||
size_t buflen)
|
||||
{
|
||||
struct hostapd_data *hapd = radius->hapd;
|
||||
struct hostapd_radius_servers *conf = radius->conf;
|
||||
int i;
|
||||
struct hostapd_radius_server *serv;
|
||||
int count = 0;
|
||||
|
||||
if (hapd->conf->auth_servers) {
|
||||
for (i = 0; i < hapd->conf->num_auth_servers; i++) {
|
||||
serv = &hapd->conf->auth_servers[i];
|
||||
if (conf->auth_servers) {
|
||||
for (i = 0; i < conf->num_auth_servers; i++) {
|
||||
serv = &conf->auth_servers[i];
|
||||
count += radius_client_dump_auth_server(
|
||||
buf + count, buflen - count, serv,
|
||||
serv == hapd->conf->auth_server ?
|
||||
serv == conf->auth_server ?
|
||||
radius : NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (hapd->conf->acct_servers) {
|
||||
for (i = 0; i < hapd->conf->num_acct_servers; i++) {
|
||||
serv = &hapd->conf->acct_servers[i];
|
||||
if (conf->acct_servers) {
|
||||
for (i = 0; i < conf->num_acct_servers; i++) {
|
||||
serv = &conf->acct_servers[i];
|
||||
count += radius_client_dump_acct_server(
|
||||
buf + count, buflen - count, serv,
|
||||
serv == hapd->conf->acct_server ?
|
||||
serv == conf->acct_server ?
|
||||
radius : NULL);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,51 @@
|
||||
#ifndef RADIUS_CLIENT_H
|
||||
#define RADIUS_CLIENT_H
|
||||
|
||||
#include "config_types.h"
|
||||
|
||||
struct radius_msg;
|
||||
|
||||
struct hostapd_radius_server {
|
||||
/* MIB prefix for shared variables:
|
||||
* @ = radiusAuth or radiusAcc depending on the type of the server */
|
||||
struct hostapd_ip_addr addr; /* @ServerAddress */
|
||||
int port; /* @ClientServerPortNumber */
|
||||
u8 *shared_secret;
|
||||
size_t shared_secret_len;
|
||||
|
||||
/* Dynamic (not from configuration file) MIB data */
|
||||
int index; /* @ServerIndex */
|
||||
int round_trip_time; /* @ClientRoundTripTime; in hundredths of a
|
||||
* second */
|
||||
u32 requests; /* @Client{Access,}Requests */
|
||||
u32 retransmissions; /* @Client{Access,}Retransmissions */
|
||||
u32 access_accepts; /* radiusAuthClientAccessAccepts */
|
||||
u32 access_rejects; /* radiusAuthClientAccessRejects */
|
||||
u32 access_challenges; /* radiusAuthClientAccessChallenges */
|
||||
u32 responses; /* radiusAccClientResponses */
|
||||
u32 malformed_responses; /* @ClientMalformed{Access,}Responses */
|
||||
u32 bad_authenticators; /* @ClientBadAuthenticators */
|
||||
u32 timeouts; /* @ClientTimeouts */
|
||||
u32 unknown_types; /* @ClientUnknownTypes */
|
||||
u32 packets_dropped; /* @ClientPacketsDropped */
|
||||
/* @ClientPendingRequests: length of hapd->radius->msgs for matching
|
||||
* msg_type */
|
||||
};
|
||||
|
||||
struct hostapd_radius_servers {
|
||||
/* RADIUS Authentication and Accounting servers in priority order */
|
||||
struct hostapd_radius_server *auth_servers, *auth_server;
|
||||
int num_auth_servers;
|
||||
struct hostapd_radius_server *acct_servers, *acct_server;
|
||||
int num_acct_servers;
|
||||
|
||||
int retry_primary_interval;
|
||||
int acct_interim_interval;
|
||||
|
||||
int msg_dumps;
|
||||
};
|
||||
|
||||
|
||||
typedef enum {
|
||||
RADIUS_AUTH,
|
||||
RADIUS_ACCT,
|
||||
@ -32,7 +77,8 @@ int radius_client_send(struct radius_client_data *radius,
|
||||
u8 radius_client_get_id(struct radius_client_data *radius);
|
||||
|
||||
void radius_client_flush(struct radius_client_data *radius);
|
||||
struct radius_client_data * radius_client_init(struct hostapd_data *hapd);
|
||||
struct radius_client_data *
|
||||
radius_client_init(void *ctx, struct hostapd_radius_servers *conf);
|
||||
void radius_client_deinit(struct radius_client_data *radius);
|
||||
void radius_client_flush_auth(struct radius_client_data *radius, u8 *addr);
|
||||
int radius_client_get_mib(struct radius_client_data *radius, char *buf,
|
||||
|
@ -53,6 +53,10 @@ struct radius_client {
|
||||
struct radius_client *next;
|
||||
struct in_addr addr;
|
||||
struct in_addr mask;
|
||||
#ifdef CONFIG_IPV6
|
||||
struct in6_addr addr6;
|
||||
struct in6_addr mask6;
|
||||
#endif /* CONFIG_IPV6 */
|
||||
char *shared_secret;
|
||||
int shared_secret_len;
|
||||
struct radius_session *sessions;
|
||||
@ -67,6 +71,7 @@ struct radius_server_data {
|
||||
int num_sess;
|
||||
void *eap_sim_db_priv;
|
||||
void *ssl_ctx;
|
||||
int ipv6;
|
||||
};
|
||||
|
||||
|
||||
@ -87,12 +92,33 @@ static void radius_server_session_timeout(void *eloop_ctx, void *timeout_ctx);
|
||||
|
||||
|
||||
static struct radius_client *
|
||||
radius_server_get_client(struct radius_server_data *data, struct in_addr *addr)
|
||||
radius_server_get_client(struct radius_server_data *data, struct in_addr *addr,
|
||||
int ipv6)
|
||||
{
|
||||
struct radius_client *client = data->clients;
|
||||
|
||||
while (client) {
|
||||
if ((client->addr.s_addr & client->mask.s_addr) ==
|
||||
#ifdef CONFIG_IPV6
|
||||
if (ipv6) {
|
||||
struct in6_addr *addr6;
|
||||
int i;
|
||||
|
||||
addr6 = (struct in6_addr *) addr;
|
||||
for (i = 0; i < 16; i++) {
|
||||
if ((addr6->s6_addr[i] &
|
||||
client->mask6.s6_addr[i]) !=
|
||||
(client->addr6.s6_addr[i] &
|
||||
client->mask6.s6_addr[i])) {
|
||||
i = 17;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == 16) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_IPV6 */
|
||||
if (!ipv6 && (client->addr.s_addr & client->mask.s_addr) ==
|
||||
(addr->s_addr & client->mask.s_addr)) {
|
||||
break;
|
||||
}
|
||||
@ -321,14 +347,15 @@ radius_server_encapsulate_eap(struct radius_server_data *data,
|
||||
static int radius_server_reject(struct radius_server_data *data,
|
||||
struct radius_client *client,
|
||||
struct radius_msg *request,
|
||||
struct sockaddr_in *from)
|
||||
struct sockaddr *from, socklen_t fromlen,
|
||||
const char *from_addr, int from_port)
|
||||
{
|
||||
struct radius_msg *msg;
|
||||
int ret = 0;
|
||||
struct eap_hdr eapfail;
|
||||
|
||||
RADIUS_DEBUG("Reject invalid request from %s:%d",
|
||||
inet_ntoa(from->sin_addr), ntohs(from->sin_port));
|
||||
from_addr, from_port);
|
||||
|
||||
msg = radius_msg_new(RADIUS_CODE_ACCESS_REJECT,
|
||||
request->hdr->identifier);
|
||||
@ -371,8 +398,9 @@ static int radius_server_reject(struct radius_server_data *data,
|
||||
|
||||
static int radius_server_request(struct radius_server_data *data,
|
||||
struct radius_msg *msg,
|
||||
struct sockaddr_in *from,
|
||||
struct radius_client *client)
|
||||
struct sockaddr *from, socklen_t fromlen,
|
||||
struct radius_client *client,
|
||||
const char *from_addr, int from_port)
|
||||
{
|
||||
u8 *eap = NULL;
|
||||
size_t eap_len;
|
||||
@ -400,13 +428,15 @@ static int radius_server_request(struct radius_server_data *data,
|
||||
RADIUS_DEBUG("Request for session 0x%x", sess->sess_id);
|
||||
} else if (state_included) {
|
||||
RADIUS_DEBUG("State attribute included but no session found");
|
||||
radius_server_reject(data, client, msg, from);
|
||||
radius_server_reject(data, client, msg, from, fromlen,
|
||||
from_addr, from_port);
|
||||
return -1;
|
||||
} else {
|
||||
sess = radius_server_get_new_session(data, client, msg);
|
||||
if (sess == NULL) {
|
||||
RADIUS_DEBUG("Could not create a new session");
|
||||
radius_server_reject(data, client, msg, from);
|
||||
radius_server_reject(data, client, msg, from, fromlen,
|
||||
from_addr, from_port);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -414,7 +444,7 @@ static int radius_server_request(struct radius_server_data *data,
|
||||
eap = radius_msg_get_eap(msg, &eap_len);
|
||||
if (eap == NULL) {
|
||||
RADIUS_DEBUG("No EAP-Message in RADIUS packet from %s",
|
||||
inet_ntoa(from->sin_addr));
|
||||
from_addr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -426,6 +456,13 @@ static int radius_server_request(struct radius_server_data *data,
|
||||
resp_id = 0;
|
||||
}
|
||||
|
||||
/* FIX: if Code is Request, Success, or Failure, send Access-Reject;
|
||||
* RFC3579 Sect. 2.6.2.
|
||||
* Include EAP-Response/Nak with no preferred method if
|
||||
* code == request.
|
||||
* If code is not 1-4, discard the packet silently.
|
||||
* Or is this already done by the EAP state machine? */
|
||||
|
||||
eap_set_eapRespData(sess->eap, eap, eap_len);
|
||||
free(eap);
|
||||
eap = NULL;
|
||||
@ -460,14 +497,13 @@ static int radius_server_request(struct radius_server_data *data,
|
||||
sess->eapReqDataLen = 0;
|
||||
|
||||
if (reply) {
|
||||
RADIUS_DEBUG("Reply to %s:%d", inet_ntoa(from->sin_addr),
|
||||
ntohs(from->sin_port));
|
||||
RADIUS_DEBUG("Reply to %s:%d", from_addr, from_port);
|
||||
if (wpa_debug_level <= MSG_MSGDUMP) {
|
||||
radius_msg_dump(reply);
|
||||
}
|
||||
|
||||
res = sendto(data->auth_sock, reply->buf, reply->buf_used, 0,
|
||||
(struct sockaddr *) from, sizeof(*from));
|
||||
(struct sockaddr *) from, fromlen);
|
||||
if (res < 0) {
|
||||
perror("sendto[RADIUS SRV]");
|
||||
}
|
||||
@ -489,11 +525,13 @@ static void radius_server_receive_auth(int sock, void *eloop_ctx,
|
||||
{
|
||||
struct radius_server_data *data = eloop_ctx;
|
||||
u8 *buf = NULL;
|
||||
struct sockaddr_in from;
|
||||
struct sockaddr_storage from;
|
||||
socklen_t fromlen;
|
||||
int len;
|
||||
struct radius_client *client;
|
||||
struct radius_client *client = NULL;
|
||||
struct radius_msg *msg = NULL;
|
||||
char abuf[50];
|
||||
int from_port = 0;
|
||||
|
||||
buf = malloc(RADIUS_MAX_MSG_LEN);
|
||||
if (buf == NULL) {
|
||||
@ -508,14 +546,36 @@ static void radius_server_receive_auth(int sock, void *eloop_ctx,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
RADIUS_DEBUG("Received %d bytes from %s:%d",
|
||||
len, inet_ntoa(from.sin_addr), ntohs(from.sin_port));
|
||||
#ifdef CONFIG_IPV6
|
||||
if (data->ipv6) {
|
||||
struct sockaddr_in6 *from6 = (struct sockaddr_in6 *) &from;
|
||||
if (inet_ntop(AF_INET6, &from6->sin6_addr, abuf, sizeof(abuf))
|
||||
== NULL)
|
||||
abuf[0] = '\0';
|
||||
from_port = ntohs(from6->sin6_port);
|
||||
RADIUS_DEBUG("Received %d bytes from %s:%d",
|
||||
len, abuf, from_port);
|
||||
|
||||
client = radius_server_get_client(data,
|
||||
(struct in_addr *)
|
||||
&from6->sin6_addr, 1);
|
||||
}
|
||||
#endif /* CONFIG_IPV6 */
|
||||
|
||||
if (!data->ipv6) {
|
||||
struct sockaddr_in *from4 = (struct sockaddr_in *) &from;
|
||||
snprintf(abuf, sizeof(abuf), "%s", inet_ntoa(from4->sin_addr));
|
||||
from_port = ntohs(from4->sin_port);
|
||||
RADIUS_DEBUG("Received %d bytes from %s:%d",
|
||||
len, abuf, from_port);
|
||||
|
||||
client = radius_server_get_client(data, &from4->sin_addr, 0);
|
||||
}
|
||||
|
||||
RADIUS_DUMP("Received data", buf, len);
|
||||
|
||||
client = radius_server_get_client(data, &from.sin_addr);
|
||||
if (client == NULL) {
|
||||
RADIUS_DEBUG("Unknown client %s - packet ignored",
|
||||
inet_ntoa(from.sin_addr));
|
||||
RADIUS_DEBUG("Unknown client %s - packet ignored", abuf);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -539,12 +599,12 @@ static void radius_server_receive_auth(int sock, void *eloop_ctx,
|
||||
|
||||
if (radius_msg_verify_msg_auth(msg, (u8 *) client->shared_secret,
|
||||
client->shared_secret_len, NULL)) {
|
||||
RADIUS_DEBUG("Invalid Message-Authenticator from %s",
|
||||
inet_ntoa(from.sin_addr));
|
||||
RADIUS_DEBUG("Invalid Message-Authenticator from %s", abuf);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
radius_server_request(data, msg, &from, client);
|
||||
radius_server_request(data, msg, (struct sockaddr *) &from, fromlen,
|
||||
client, abuf, from_port);
|
||||
|
||||
fail:
|
||||
if (msg) {
|
||||
@ -579,6 +639,33 @@ static int radius_server_open_socket(int port)
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_IPV6
|
||||
static int radius_server_open_socket6(int port)
|
||||
{
|
||||
int s;
|
||||
struct sockaddr_in6 addr;
|
||||
|
||||
s = socket(PF_INET6, SOCK_DGRAM, 0);
|
||||
if (s < 0) {
|
||||
perror("socket[IPv6]");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin6_family = AF_INET6;
|
||||
memcpy(&addr.sin6_addr, &in6addr_any, sizeof(in6addr_any));
|
||||
addr.sin6_port = htons(port);
|
||||
if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
|
||||
perror("bind");
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
#endif /* CONFIG_IPV6 */
|
||||
|
||||
|
||||
static void radius_server_free_sessions(struct radius_server_data *data,
|
||||
struct radius_session *sessions)
|
||||
{
|
||||
@ -611,7 +698,7 @@ static void radius_server_free_clients(struct radius_server_data *data,
|
||||
|
||||
|
||||
static struct radius_client *
|
||||
radius_server_read_clients(const char *client_file)
|
||||
radius_server_read_clients(const char *client_file, int ipv6)
|
||||
{
|
||||
FILE *f;
|
||||
const int buf_size = 1024;
|
||||
@ -619,6 +706,9 @@ radius_server_read_clients(const char *client_file)
|
||||
struct radius_client *clients, *tail, *entry;
|
||||
int line = 0, mask, failed = 0, i;
|
||||
struct in_addr addr;
|
||||
#ifdef CONFIG_IPV6
|
||||
struct in6_addr addr6;
|
||||
#endif /* CONFIG_IPV6 */
|
||||
unsigned int val;
|
||||
|
||||
f = fopen(client_file, "r");
|
||||
@ -638,6 +728,7 @@ radius_server_read_clients(const char *client_file)
|
||||
/* Configuration file format:
|
||||
* 192.168.1.0/24 secret
|
||||
* 192.168.1.2 secret
|
||||
* fe80::211:22ff:fe33:4455/64 secretipv6
|
||||
*/
|
||||
line++;
|
||||
buf[buf_size - 1] = '\0';
|
||||
@ -650,7 +741,9 @@ radius_server_read_clients(const char *client_file)
|
||||
continue;
|
||||
|
||||
pos = buf;
|
||||
while ((*pos >= '0' && *pos <= '9') || *pos == '.') {
|
||||
while ((*pos >= '0' && *pos <= '9') || *pos == '.' ||
|
||||
(*pos >= 'a' && *pos <= 'f') || *pos == ':' ||
|
||||
(*pos >= 'A' && *pos <= 'F')) {
|
||||
pos++;
|
||||
}
|
||||
|
||||
@ -663,20 +756,36 @@ radius_server_read_clients(const char *client_file)
|
||||
char *end;
|
||||
*pos++ = '\0';
|
||||
mask = strtol(pos, &end, 10);
|
||||
if ((pos == end) || (mask < 0 || mask > 32)) {
|
||||
if ((pos == end) ||
|
||||
(mask < 0 || mask > (ipv6 ? 128 : 32))) {
|
||||
failed = 1;
|
||||
break;
|
||||
}
|
||||
pos = end;
|
||||
} else {
|
||||
mask = 32;
|
||||
mask = ipv6 ? 128 : 32;
|
||||
*pos++ = '\0';
|
||||
}
|
||||
|
||||
if (inet_aton(buf, &addr) == 0) {
|
||||
if (!ipv6 && inet_aton(buf, &addr) == 0) {
|
||||
failed = 1;
|
||||
break;
|
||||
}
|
||||
#ifdef CONFIG_IPV6
|
||||
if (ipv6 && inet_pton(AF_INET6, buf, &addr6) <= 0) {
|
||||
if (inet_pton(AF_INET, buf, &addr) <= 0) {
|
||||
failed = 1;
|
||||
break;
|
||||
}
|
||||
/* Convert IPv4 address to IPv6 */
|
||||
if (mask <= 32)
|
||||
mask += (128 - 32);
|
||||
memset(addr6.s6_addr, 0, 10);
|
||||
addr6.s6_addr[10] = 0xff;
|
||||
addr6.s6_addr[11] = 0xff;
|
||||
memcpy(addr6.s6_addr + 12, (char *) &addr.s_addr, 4);
|
||||
}
|
||||
#endif /* CONFIG_IPV6 */
|
||||
|
||||
while (*pos == ' ' || *pos == '\t') {
|
||||
pos++;
|
||||
@ -701,10 +810,25 @@ radius_server_read_clients(const char *client_file)
|
||||
}
|
||||
entry->shared_secret_len = strlen(entry->shared_secret);
|
||||
entry->addr.s_addr = addr.s_addr;
|
||||
val = 0;
|
||||
for (i = 0; i < mask; i++)
|
||||
val |= 1 << (31 - i);
|
||||
entry->mask.s_addr = htonl(val);
|
||||
if (!ipv6) {
|
||||
val = 0;
|
||||
for (i = 0; i < mask; i++)
|
||||
val |= 1 << (31 - i);
|
||||
entry->mask.s_addr = htonl(val);
|
||||
}
|
||||
#ifdef CONFIG_IPV6
|
||||
if (ipv6) {
|
||||
int offset = mask / 8;
|
||||
|
||||
memcpy(entry->addr6.s6_addr, addr6.s6_addr, 16);
|
||||
memset(entry->mask6.s6_addr, 0xff, offset);
|
||||
val = 0;
|
||||
for (i = 0; i < (mask % 8); i++)
|
||||
val |= 1 << (7 - i);
|
||||
if (offset < 16)
|
||||
entry->mask6.s6_addr[offset] = val;
|
||||
}
|
||||
#endif /* CONFIG_IPV6 */
|
||||
|
||||
if (tail == NULL) {
|
||||
clients = tail = entry;
|
||||
@ -732,6 +856,14 @@ radius_server_init(struct radius_server_conf *conf)
|
||||
{
|
||||
struct radius_server_data *data;
|
||||
|
||||
#ifndef CONFIG_IPV6
|
||||
if (conf->ipv6) {
|
||||
fprintf(stderr, "RADIUS server compiled without IPv6 "
|
||||
"support.\n");
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_IPV6 */
|
||||
|
||||
data = malloc(sizeof(*data));
|
||||
if (data == NULL) {
|
||||
return NULL;
|
||||
@ -740,14 +872,21 @@ radius_server_init(struct radius_server_conf *conf)
|
||||
data->hostapd_conf = conf->hostapd_conf;
|
||||
data->eap_sim_db_priv = conf->eap_sim_db_priv;
|
||||
data->ssl_ctx = conf->ssl_ctx;
|
||||
data->ipv6 = conf->ipv6;
|
||||
|
||||
data->clients = radius_server_read_clients(conf->client_file);
|
||||
data->clients = radius_server_read_clients(conf->client_file,
|
||||
conf->ipv6);
|
||||
if (data->clients == NULL) {
|
||||
printf("No RADIUS clients configured.\n");
|
||||
radius_server_deinit(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IPV6
|
||||
if (conf->ipv6)
|
||||
data->auth_sock = radius_server_open_socket6(conf->auth_port);
|
||||
else
|
||||
#endif /* CONFIG_IPV6 */
|
||||
data->auth_sock = radius_server_open_socket(conf->auth_port);
|
||||
if (data->auth_sock < 0) {
|
||||
printf("Failed to open UDP socket for RADIUS authentication "
|
||||
|
@ -9,6 +9,7 @@ struct radius_server_conf {
|
||||
void *hostapd_conf;
|
||||
void *eap_sim_db_priv;
|
||||
void *ssl_ctx;
|
||||
int ipv6;
|
||||
};
|
||||
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
/*
|
||||
* Host AP (software wireless LAN access point) user space daemon for
|
||||
* Host AP kernel driver / RC4
|
||||
* Copyright (c) 2002-2004, Jouni Malinen <jkmaline@cc.hut.fi>
|
||||
* RC4 stream cipher
|
||||
* Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@ -19,7 +18,20 @@
|
||||
|
||||
#define S_SWAP(a,b) do { u8 t = S[a]; S[a] = S[b]; S[b] = t; } while(0)
|
||||
|
||||
void rc4_skip(u8 *key, size_t keylen, size_t skip, u8 *data, size_t data_len)
|
||||
/**
|
||||
* rc4 - XOR RC4 stream to given data with skip-stream-start
|
||||
* @key: RC4 key
|
||||
* @keylen: RC4 key length
|
||||
* @skip: number of bytes to skip from the beginning of the RC4 stream
|
||||
* @data: data to be XOR'ed with RC4 stream
|
||||
* @data_len: buf length
|
||||
*
|
||||
* Generate RC4 pseudo random stream for the given key, skip beginning of the
|
||||
* stream, and XOR the end result with the data buffer to perform RC4
|
||||
* encryption/decryption.
|
||||
*/
|
||||
void rc4_skip(const u8 *key, size_t keylen, size_t skip,
|
||||
u8 *data, size_t data_len)
|
||||
{
|
||||
u32 i, j, k;
|
||||
u8 S[256], *pos;
|
||||
@ -57,7 +69,17 @@ void rc4_skip(u8 *key, size_t keylen, size_t skip, u8 *data, size_t data_len)
|
||||
}
|
||||
|
||||
|
||||
void rc4(u8 *buf, size_t len, u8 *key, size_t key_len)
|
||||
/**
|
||||
* rc4 - XOR RC4 stream to given data
|
||||
* @buf: data to be XOR'ed with RC4 stream
|
||||
* @len: buf length
|
||||
* @key: RC4 key
|
||||
* @key_len: RC4 key length
|
||||
*
|
||||
* Generate RC4 pseudo random stream for the given key and XOR this with the
|
||||
* data buffer to perform RC4 encryption/decryption.
|
||||
*/
|
||||
void rc4(u8 *buf, size_t len, const u8 *key, size_t key_len)
|
||||
{
|
||||
rc4_skip(key, key_len, 0, buf, len);
|
||||
}
|
||||
|
@ -1,7 +1,22 @@
|
||||
/*
|
||||
* RC4 stream cipher
|
||||
* Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#ifndef RC4_H
|
||||
#define RC4_H
|
||||
|
||||
void rc4_skip(u8 *key, size_t keylen, size_t skip, u8 *data, size_t data_len);
|
||||
void rc4(u8 *buf, size_t len, u8 *key, size_t key_len);
|
||||
void rc4_skip(const u8 *key, size_t keylen, size_t skip,
|
||||
u8 *data, size_t data_len);
|
||||
void rc4(u8 *buf, size_t len, const u8 *key, size_t key_len);
|
||||
|
||||
#endif /* RC4_H */
|
||||
|
@ -19,36 +19,38 @@
|
||||
#include "common.h"
|
||||
#include "sha1.h"
|
||||
#include "md5.h"
|
||||
#include "crypto.h"
|
||||
|
||||
|
||||
void sha1_mac(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
|
||||
u8 *mac)
|
||||
{
|
||||
SHA1_CTX context;
|
||||
SHA1Init(&context);
|
||||
SHA1Update(&context, key, key_len);
|
||||
SHA1Update(&context, data, data_len);
|
||||
SHA1Update(&context, key, key_len);
|
||||
SHA1Final(mac, &context);
|
||||
}
|
||||
|
||||
|
||||
/* HMAC code is based on RFC 2104 */
|
||||
/**
|
||||
* hmac_sha1_vector - HMAC-SHA1 over data vector (RFC 2104)
|
||||
* @key: Key for HMAC operations
|
||||
* @key_len: Length of the key in bytes
|
||||
* @num_elem: Number of elements in the data vector
|
||||
* @addr: Pointers to the data areas
|
||||
* @len: Lengths of the data blocks
|
||||
* @mac: Buffer for the hash (20 bytes)
|
||||
*/
|
||||
void hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
|
||||
const u8 *addr[], const size_t *len, u8 *mac)
|
||||
{
|
||||
SHA1_CTX context;
|
||||
unsigned char k_ipad[65]; /* inner padding - key XORd with ipad */
|
||||
unsigned char k_opad[65]; /* outer padding - key XORd with opad */
|
||||
unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */
|
||||
unsigned char tk[20];
|
||||
int i;
|
||||
const u8 *_addr[6];
|
||||
size_t _len[6];
|
||||
|
||||
if (num_elem > 5) {
|
||||
/*
|
||||
* Fixed limit on the number of fragments to avoid having to
|
||||
* allocate memory (which could fail).
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
/* if key is longer than 64 bytes reset it to key = SHA1(key) */
|
||||
if (key_len > 64) {
|
||||
SHA1Init(&context);
|
||||
SHA1Update(&context, key, key_len);
|
||||
SHA1Final(tk, &context);
|
||||
|
||||
sha1_vector(1, &key, &key_len, tk);
|
||||
key = tk;
|
||||
key_len = 20;
|
||||
}
|
||||
@ -62,35 +64,45 @@ void hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
|
||||
* opad is the byte 0x5c repeated 64 times
|
||||
* and text is the data being protected */
|
||||
|
||||
/* start out by storing key in pads */
|
||||
memset(k_ipad, 0, sizeof(k_ipad));
|
||||
memset(k_opad, 0, sizeof(k_opad));
|
||||
memcpy(k_ipad, key, key_len);
|
||||
memcpy(k_opad, key, key_len);
|
||||
|
||||
/* XOR key with ipad and opad values */
|
||||
for (i = 0; i < 64; i++) {
|
||||
k_ipad[i] ^= 0x36;
|
||||
k_opad[i] ^= 0x5c;
|
||||
}
|
||||
/* start out by storing key in ipad */
|
||||
memset(k_pad, 0, sizeof(k_pad));
|
||||
memcpy(k_pad, key, key_len);
|
||||
/* XOR key with ipad values */
|
||||
for (i = 0; i < 64; i++)
|
||||
k_pad[i] ^= 0x36;
|
||||
|
||||
/* perform inner SHA1 */
|
||||
SHA1Init(&context); /* init context for 1st pass */
|
||||
SHA1Update(&context, k_ipad, 64); /* start with inner pad */
|
||||
/* then text of datagram; all fragments */
|
||||
_addr[0] = k_pad;
|
||||
_len[0] = 64;
|
||||
for (i = 0; i < num_elem; i++) {
|
||||
SHA1Update(&context, addr[i], len[i]);
|
||||
_addr[i + 1] = addr[i];
|
||||
_len[i + 1] = len[i];
|
||||
}
|
||||
SHA1Final(mac, &context); /* finish up 1st pass */
|
||||
sha1_vector(1 + num_elem, _addr, _len, mac);
|
||||
|
||||
memset(k_pad, 0, sizeof(k_pad));
|
||||
memcpy(k_pad, key, key_len);
|
||||
/* XOR key with opad values */
|
||||
for (i = 0; i < 64; i++)
|
||||
k_pad[i] ^= 0x5c;
|
||||
|
||||
/* perform outer SHA1 */
|
||||
SHA1Init(&context); /* init context for 2nd pass */
|
||||
SHA1Update(&context, k_opad, 64); /* start with outer pad */
|
||||
SHA1Update(&context, mac, 20); /* then results of 1st hash */
|
||||
SHA1Final(mac, &context); /* finish up 2nd pass */
|
||||
_addr[0] = k_pad;
|
||||
_len[0] = 64;
|
||||
_addr[1] = mac;
|
||||
_len[1] = SHA1_MAC_LEN;
|
||||
sha1_vector(2, _addr, _len, mac);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hmac_sha1 - HMAC-SHA1 over data buffer (RFC 2104)
|
||||
* @key: Key for HMAC operations
|
||||
* @key_len: Length of the key in bytes
|
||||
* @data: Pointers to the data area
|
||||
* @data_len: Length of the data area
|
||||
* @mac: Buffer for the hash (20 bytes)
|
||||
*/
|
||||
void hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
|
||||
u8 *mac)
|
||||
{
|
||||
@ -98,6 +110,19 @@ void hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* sha1_prf - SHA1-based Pseudo-Random Function (PRF) (IEEE 802.11i, 8.5.1.1)
|
||||
* @key: Key for PRF
|
||||
* @key_len: Length of the key in bytes
|
||||
* @label: A unique label for each purpose of the PRF
|
||||
* @data: Extra data to bind into the key
|
||||
* @data_len: Length of the data
|
||||
* @buf: Buffer for the generated pseudo-random key
|
||||
* @buf_len: Number of bytes of key to generate
|
||||
*
|
||||
* This function is used to derive new, cryptographically separate keys from a
|
||||
* given key (e.g., PMK in IEEE 802.11i).
|
||||
*/
|
||||
void sha1_prf(const u8 *key, size_t key_len, const char *label,
|
||||
const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
|
||||
{
|
||||
@ -135,7 +160,20 @@ void sha1_prf(const u8 *key, size_t key_len, const char *label,
|
||||
}
|
||||
|
||||
|
||||
/* draft-cam-winget-eap-fast-00.txt */
|
||||
/**
|
||||
* sha1_t_prf - EAP-FAST Pseudo-Random Function (T-PRF)
|
||||
* @key: Key for PRF
|
||||
* @key_len: Length of the key in bytes
|
||||
* @label: A unique label for each purpose of the PRF
|
||||
* @seed: Seed value to bind into the key
|
||||
* @seed_len: Length of the seed
|
||||
* @buf: Buffer for the generated pseudo-random key
|
||||
* @buf_len: Number of bytes of key to generate
|
||||
*
|
||||
* This function is used to derive new, cryptographically separate keys from a
|
||||
* given key for EAP-FAST. T-PRF is defined in
|
||||
* draft-cam-winget-eap-fast-02.txt, Appendix B.
|
||||
*/
|
||||
void sha1_t_prf(const u8 *key, size_t key_len, const char *label,
|
||||
const u8 *seed, size_t seed_len, u8 *buf, size_t buf_len)
|
||||
{
|
||||
@ -177,7 +215,19 @@ void sha1_t_prf(const u8 *key, size_t key_len, const char *label,
|
||||
}
|
||||
|
||||
|
||||
/* RFC 2246 */
|
||||
/**
|
||||
* tls_prf - Pseudo-Random Function for TLS (TLS-PRF, RFC 2246)
|
||||
* @secret: Key for PRF
|
||||
* @secret_len: Length of the key in bytes
|
||||
* @label: A unique label for each purpose of the PRF
|
||||
* @seed: Seed value to bind into the key
|
||||
* @seed_len: Length of the seed
|
||||
* @out: Buffer for the generated pseudo-random key
|
||||
* @outlen: Number of bytes of key to generate
|
||||
*
|
||||
* This function is used to derive new, cryptographically separate keys from a
|
||||
* given key in TLS. This PRF is defined in RFC 2246, Chapter 5.
|
||||
*/
|
||||
int tls_prf(const u8 *secret, size_t secret_len, const char *label,
|
||||
const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
|
||||
{
|
||||
@ -285,6 +335,19 @@ static void pbkdf2_sha1_f(const char *passphrase, const char *ssid,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* pbkdf2_sha1 - SHA1-based key derivation function (PBKDF2) for IEEE 802.11i
|
||||
* @passphrase: ASCII passphrase
|
||||
* @ssid: SSID
|
||||
* @ssid_len: SSID length in bytes
|
||||
* @interations: Number of iterations to run
|
||||
* @buf: Buffer for the generated key
|
||||
* @buflen: Length of the buffer in bytes
|
||||
*
|
||||
* This function is used to derive PSK for WPA-PSK. For this protocol,
|
||||
* iterations is set to 4096 and buflen to 32. This function is described in
|
||||
* IEEE Std 802.11-2004, Clause H.4. The main construction is from PKCS#5 v2.0.
|
||||
*/
|
||||
void pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len,
|
||||
int iterations, u8 *buf, size_t buflen)
|
||||
{
|
||||
@ -305,20 +368,27 @@ void pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len,
|
||||
}
|
||||
|
||||
|
||||
void sha1_transform(u8 *state, u8 data[64])
|
||||
{
|
||||
#ifdef EAP_TLS_FUNCS
|
||||
SHA_CTX context;
|
||||
memset(&context, 0, sizeof(context));
|
||||
memcpy(&context.h0, state, 5 * 4);
|
||||
SHA1_Transform(&context, data);
|
||||
memcpy(state, &context.h0, 5 * 4);
|
||||
#else /* EAP_TLS_FUNCS */
|
||||
SHA1Transform((u32 *) state, data);
|
||||
#endif /* EAP_TLS_FUNCS */
|
||||
}
|
||||
#ifndef EAP_TLS_FUNCS
|
||||
|
||||
typedef struct {
|
||||
u32 state[5];
|
||||
u32 count[2];
|
||||
unsigned char buffer[64];
|
||||
} SHA1_CTX;
|
||||
|
||||
static void SHA1Init(SHA1_CTX *context);
|
||||
static void SHA1Update(SHA1_CTX *context, const void *data, u32 len);
|
||||
static void SHA1Final(unsigned char digest[20], SHA1_CTX* context);
|
||||
static void SHA1Transform(u32 state[5], const unsigned char buffer[64]);
|
||||
|
||||
|
||||
/**
|
||||
* sha1_vector - SHA-1 hash for data vector
|
||||
* @num_elem: Number of elements in the data vector
|
||||
* @addr: Pointers to the data areas
|
||||
* @len: Lengths of the data blocks
|
||||
* @mac: Buffer for the hash
|
||||
*/
|
||||
void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len,
|
||||
u8 *mac)
|
||||
{
|
||||
@ -332,7 +402,21 @@ void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len,
|
||||
}
|
||||
|
||||
|
||||
#ifndef EAP_TLS_FUNCS
|
||||
/**
|
||||
* sha1_transform - Perform one SHA-1 transform step
|
||||
* @state: SHA-1 state
|
||||
* @data: Input data for the SHA-1 transform
|
||||
*
|
||||
* This function is used to implement random number generation specified in
|
||||
* NIST FIPS Publication 186-2 for EAP-SIM. This PRF uses a function that is
|
||||
* similar to SHA-1, but has different message padding and as such, access to
|
||||
* just part of the SHA-1 is needed.
|
||||
*/
|
||||
void sha1_transform(u8 *state, const u8 data[64])
|
||||
{
|
||||
SHA1Transform((u32 *) state, data);
|
||||
}
|
||||
|
||||
|
||||
/* ===== start - public domain SHA1 implementation ===== */
|
||||
|
||||
@ -462,7 +546,7 @@ void SHAPrintContext(SHA1_CTX *context, char *msg)
|
||||
|
||||
/* Hash a single 512-bit block. This is the core of the algorithm. */
|
||||
|
||||
void SHA1Transform(u32 state[5], const unsigned char buffer[64])
|
||||
static void SHA1Transform(u32 state[5], const unsigned char buffer[64])
|
||||
{
|
||||
u32 a, b, c, d, e;
|
||||
typedef union {
|
||||
@ -520,7 +604,7 @@ void SHA1Transform(u32 state[5], const unsigned char buffer[64])
|
||||
|
||||
/* SHA1Init - Initialize new context */
|
||||
|
||||
void SHA1Init(SHA1_CTX* context)
|
||||
static void SHA1Init(SHA1_CTX* context)
|
||||
{
|
||||
/* SHA1 initialization constants */
|
||||
context->state[0] = 0x67452301;
|
||||
@ -534,7 +618,7 @@ void SHA1Init(SHA1_CTX* context)
|
||||
|
||||
/* Run your data through this. */
|
||||
|
||||
void SHA1Update(SHA1_CTX* context, const void *_data, u32 len)
|
||||
static void SHA1Update(SHA1_CTX* context, const void *_data, u32 len)
|
||||
{
|
||||
u32 i, j;
|
||||
const unsigned char *data = _data;
|
||||
@ -564,7 +648,7 @@ void SHA1Update(SHA1_CTX* context, const void *_data, u32 len)
|
||||
|
||||
/* Add padding and return the message digest. */
|
||||
|
||||
void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
|
||||
static void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
|
||||
{
|
||||
u32 i;
|
||||
unsigned char finalcount[8];
|
||||
|
@ -1,36 +1,22 @@
|
||||
/*
|
||||
* SHA1 hash implementation and interface functions
|
||||
* Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#ifndef SHA1_H
|
||||
#define SHA1_H
|
||||
|
||||
#ifdef EAP_TLS_FUNCS
|
||||
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#define SHA1_CTX SHA_CTX
|
||||
#define SHA1Init SHA1_Init
|
||||
#define SHA1Update SHA1_Update
|
||||
#define SHA1Final SHA1_Final
|
||||
#define SHA1Transform SHA1_Transform
|
||||
#define SHA1_MAC_LEN SHA_DIGEST_LENGTH
|
||||
|
||||
#else /* EAP_TLS_FUNCS */
|
||||
|
||||
#define SHA1_MAC_LEN 20
|
||||
|
||||
typedef struct {
|
||||
u32 state[5];
|
||||
u32 count[2];
|
||||
unsigned char buffer[64];
|
||||
} SHA1_CTX;
|
||||
|
||||
void SHA1Init(SHA1_CTX *context);
|
||||
void SHA1Update(SHA1_CTX *context, const void *data, u32 len);
|
||||
void SHA1Final(unsigned char digest[20], SHA1_CTX* context);
|
||||
void SHA1Transform(u32 state[5], const unsigned char buffer[64]);
|
||||
|
||||
#endif /* EAP_TLS_FUNCS */
|
||||
|
||||
void sha1_mac(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
|
||||
u8 *mac);
|
||||
void hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
|
||||
const u8 *addr[], const size_t *len, u8 *mac);
|
||||
void hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
|
||||
@ -43,8 +29,5 @@ int tls_prf(const u8 *secret, size_t secret_len, const char *label,
|
||||
const u8 *seed, size_t seed_len, u8 *out, size_t outlen);
|
||||
void pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len,
|
||||
int iterations, u8 *buf, size_t buflen);
|
||||
void sha1_transform(u8 *state, u8 data[64]);
|
||||
void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len,
|
||||
u8 *mac);
|
||||
|
||||
#endif /* SHA1_H */
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "wpa.h"
|
||||
#include "radius_client.h"
|
||||
#include "driver.h"
|
||||
#include "hostap_common.h"
|
||||
|
||||
|
||||
int ap_for_each_sta(struct hostapd_data *hapd,
|
||||
@ -49,7 +50,7 @@ int ap_for_each_sta(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
|
||||
struct sta_info* ap_get_sta(hostapd *hapd, u8 *sta)
|
||||
struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta)
|
||||
{
|
||||
struct sta_info *s;
|
||||
|
||||
@ -317,7 +318,7 @@ void ap_sta_no_session_timeout(hostapd *hapd, struct sta_info *sta)
|
||||
}
|
||||
|
||||
|
||||
struct sta_info * ap_sta_add(struct hostapd_data *hapd, u8 *addr)
|
||||
struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
|
||||
{
|
||||
struct sta_info *sta;
|
||||
|
||||
@ -339,7 +340,7 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, u8 *addr)
|
||||
return NULL;
|
||||
}
|
||||
memset(sta, 0, sizeof(struct sta_info));
|
||||
sta->acct_interim_interval = hapd->conf->radius_acct_interim_interval;
|
||||
sta->acct_interim_interval = hapd->conf->radius->acct_interim_interval;
|
||||
|
||||
/* initialize STA info data */
|
||||
eloop_register_timeout(AP_MAX_INACTIVITY, 0, ap_handle_timer,
|
||||
|
@ -5,7 +5,7 @@ int ap_for_each_sta(struct hostapd_data *hapd,
|
||||
int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
void *ctx),
|
||||
void *ctx);
|
||||
struct sta_info* ap_get_sta(hostapd *hapd, u8 *sta);
|
||||
struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta);
|
||||
void ap_sta_hash_add(hostapd *hapd, struct sta_info *sta);
|
||||
void ap_free_sta(hostapd *hapd, struct sta_info *sta);
|
||||
void ap_free_sta(hostapd *hapd, struct sta_info *sta);
|
||||
@ -14,6 +14,6 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx);
|
||||
void ap_sta_session_timeout(hostapd *hapd, struct sta_info *sta,
|
||||
u32 session_timeout);
|
||||
void ap_sta_no_session_timeout(hostapd *hapd, struct sta_info *sta);
|
||||
struct sta_info * ap_sta_add(struct hostapd_data *hapd, u8 *addr);
|
||||
struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr);
|
||||
|
||||
#endif /* STA_INFO_H */
|
||||
|
@ -1,3 +1,17 @@
|
||||
/*
|
||||
* WPA Supplicant / SSL/TLS interface definition
|
||||
* Copyright (c) 2004-2006, Jouni Malinen <jkmaline@cc.hut.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#ifndef TLS_H
|
||||
#define TLS_H
|
||||
|
||||
@ -10,28 +24,115 @@ struct tls_keys {
|
||||
size_t client_random_len;
|
||||
const u8 *server_random;
|
||||
size_t server_random_len;
|
||||
|
||||
/*
|
||||
* If TLS library does not provide access to master_key, but only to
|
||||
* EAP key block, this pointer can be set to point to the result of
|
||||
* PRF(master_secret, "client EAP encryption",
|
||||
* client_random + server_random).
|
||||
*/
|
||||
const u8 *eap_tls_prf;
|
||||
size_t eap_tls_prf_len;
|
||||
};
|
||||
|
||||
struct tls_config {
|
||||
const char *opensc_engine_path;
|
||||
const char *pkcs11_engine_path;
|
||||
const char *pkcs11_module_path;
|
||||
};
|
||||
|
||||
/**
|
||||
* tls_init - initialize TLS library
|
||||
* struct tls_connection_params - Parameters for TLS connection
|
||||
* @ca_cert: File or reference name for CA X.509 certificate in PEM or DER
|
||||
* format
|
||||
* @ca_cert_blob: ca_cert as inlined data or %NULL if not used
|
||||
* @ca_cert_blob_len: ca_cert_blob length
|
||||
* @ca_path: Path to CA certificates (OpenSSL specific)
|
||||
* @subject_match: String to match in the subject of the peer certificate or
|
||||
* %NULL to allow all subjects
|
||||
* @altsubject_match: String to match in the alternative subject of the peer
|
||||
* certificate or %NULL to allow all alternative subjects
|
||||
* @client_cert: File or reference name for client X.509 certificate in PEM or
|
||||
* DER format
|
||||
* @client_cert_blob: client_cert as inlined data or %NULL if not used
|
||||
* @client_cert_blob_len: client_cert_blob length
|
||||
* @private_key: File or reference name for client private key in PEM or DER
|
||||
* format (traditional format (RSA PRIVATE KEY) or PKCS#8 (PRIVATE KEY)
|
||||
* @private_key_blob: private_key as inlined data or %NULL if not used
|
||||
* @private_key_blob_len: private_key_blob length
|
||||
* @private_key_passwd: Passphrase for decrypted private key, %NULL if no
|
||||
* passphrase is used.
|
||||
* @dh_file: File name for DH/DSA data in PEM format, or %NULL if not used
|
||||
* @dh_blob: dh_file as inlined data or %NULL if not used
|
||||
* @dh_blob_len: dh_blob length
|
||||
* @engine: 1 = use engine (e.g., a smartcard) for private key operations
|
||||
* (this is OpenSSL specific for now)
|
||||
* @engine_id: engine id string (this is OpenSSL specific for now)
|
||||
* @ppin: pointer to the pin variable in the configuration
|
||||
* (this is OpenSSL specific for now)
|
||||
* @key_id: the private key's key id (this is OpenSSL specific for now)
|
||||
*
|
||||
* Returns: Context data to be used as @tls_ctx in calls to other functions,
|
||||
* or %NULL on failure.
|
||||
* TLS connection parameters to be configured with tls_connection_set_params().
|
||||
*
|
||||
* Called once during program startup.
|
||||
* Certificates and private key can be configured either as a reference name
|
||||
* (file path or reference to certificate store) or by providing the same data
|
||||
* as a pointer to the data in memory. Only one option will be used for each
|
||||
* field.
|
||||
*/
|
||||
void * tls_init(void);
|
||||
struct tls_connection_params {
|
||||
const char *ca_cert;
|
||||
const u8 *ca_cert_blob;
|
||||
size_t ca_cert_blob_len;
|
||||
const char *ca_path;
|
||||
const char *subject_match;
|
||||
const char *altsubject_match;
|
||||
const char *client_cert;
|
||||
const u8 *client_cert_blob;
|
||||
size_t client_cert_blob_len;
|
||||
const char *private_key;
|
||||
const u8 *private_key_blob;
|
||||
size_t private_key_blob_len;
|
||||
const char *private_key_passwd;
|
||||
const char *dh_file;
|
||||
const u8 *dh_blob;
|
||||
size_t dh_blob_len;
|
||||
|
||||
/* OpenSSL specific variables */
|
||||
int engine;
|
||||
const char *engine_id;
|
||||
const char *pin;
|
||||
const char *key_id;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* tls_deinit - deinitialize TLS library
|
||||
* tls_init - Initialize TLS library
|
||||
* @conf: Configuration data for TLS library
|
||||
* Returns: Context data to be used as tls_ctx in calls to other functions,
|
||||
* or %NULL on failure.
|
||||
*
|
||||
* Called once during program startup and once for each RSN pre-authentication
|
||||
* session. In other words, there can be two concurrent TLS contexts. If global
|
||||
* library initialization is needed (i.e., one that is shared between both
|
||||
* authentication types), the TLS library wrapper should maintain a reference
|
||||
* counter and do global initialization only when moving from 0 to 1 reference.
|
||||
*/
|
||||
void * tls_init(const struct tls_config *conf);
|
||||
|
||||
/**
|
||||
* tls_deinit - Deinitialize TLS library
|
||||
* @tls_ctx: TLS context data from tls_init()
|
||||
*
|
||||
* Called once during program shutdown.
|
||||
* Called once during program shutdown and once for each RSN pre-authentication
|
||||
* session. If global library deinitialization is needed (i.e., one that is
|
||||
* shared between both authentication types), the TLS library wrapper should
|
||||
* maintain a reference counter and do global deinitialization only when moving
|
||||
* from 1 to 0 references.
|
||||
*/
|
||||
void tls_deinit(void *tls_ctx);
|
||||
|
||||
/**
|
||||
* tls_get_errors - process pending errors
|
||||
* tls_get_errors - Process pending errors
|
||||
* @tls_ctx: TLS context data from tls_init()
|
||||
*
|
||||
* Returns: Number of found error, 0 if no errors detected.
|
||||
@ -41,15 +142,15 @@ void tls_deinit(void *tls_ctx);
|
||||
int tls_get_errors(void *tls_ctx);
|
||||
|
||||
/**
|
||||
* tls_connection_init - initialize a new TLS connection
|
||||
* tls_connection_init - Initialize a new TLS connection
|
||||
* @tls_ctx: TLS context data from tls_init()
|
||||
*
|
||||
* Returns: Connection context data, @conn for other function calls
|
||||
* Returns: Connection context data, conn for other function calls
|
||||
*/
|
||||
struct tls_connection * tls_connection_init(void *tls_ctx);
|
||||
|
||||
/**
|
||||
* tls_connection_deinit - free TLS connection data
|
||||
* tls_connection_deinit - Free TLS connection data
|
||||
* @tls_ctx: TLS context data from tls_init()
|
||||
* @conn: Connection context data from tls_connection_init()
|
||||
*
|
||||
@ -58,7 +159,7 @@ struct tls_connection * tls_connection_init(void *tls_ctx);
|
||||
void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn);
|
||||
|
||||
/**
|
||||
* tls_connection_established - has the TLS connection been completed?
|
||||
* tls_connection_established - Has the TLS connection been completed?
|
||||
* @tls_ctx: TLS context data from tls_init()
|
||||
* @conn: Connection context data from tls_connection_init()
|
||||
*
|
||||
@ -67,34 +168,40 @@ void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn);
|
||||
int tls_connection_established(void *tls_ctx, struct tls_connection *conn);
|
||||
|
||||
/**
|
||||
* tls_connection_shutdown - shutdown TLS connection data.
|
||||
* tls_connection_shutdown - Shutdown TLS connection data.
|
||||
* @tls_ctx: TLS context data from tls_init()
|
||||
* @conn: Connection context data from tls_connection_init()
|
||||
*
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*
|
||||
* Shutdown current TLS connection without releasing all resources. New
|
||||
* connection can be started by using the same @conn without having to call
|
||||
* connection can be started by using the same conn without having to call
|
||||
* tls_connection_init() or setting certificates etc. again. The new
|
||||
* connection should try to use session resumption.
|
||||
*/
|
||||
int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn);
|
||||
|
||||
enum {
|
||||
TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED = -3,
|
||||
TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED = -2
|
||||
};
|
||||
/**
|
||||
* tls_connection_ca_cert - set trusted CA certificate for TLS connection
|
||||
* tls_connection_set_params - Set TLS connection parameters
|
||||
* @tls_ctx: TLS context data from tls_init()
|
||||
* @conn: Connection context data from tls_connection_init()
|
||||
* @ca_cert: File name for CA certificate in PEM or DER format
|
||||
* @subject_match: String to match in the subject of the peer certificate or
|
||||
* %NULL to allow all subjects
|
||||
* @params: Connection parameters
|
||||
*
|
||||
* Returns: 0 on success, -1 on failure
|
||||
* Returns: 0 on success, -1 on failure,
|
||||
* TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on possible PIN error causing
|
||||
* PKCS#11 engine failure, or
|
||||
* TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED (-3) on failure to verify the
|
||||
* PKCS#11 engine private key.
|
||||
*/
|
||||
int tls_connection_ca_cert(void *tls_ctx, struct tls_connection *conn,
|
||||
const char *ca_cert, const char *subject_match);
|
||||
int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
|
||||
const struct tls_connection_params *params);
|
||||
|
||||
/**
|
||||
* tls_global_ca_cert - set trusted CA certificate for all TLS connections
|
||||
* tls_global_ca_cert - Set trusted CA certificate for all TLS connections
|
||||
* @tls_ctx: TLS context data from tls_init()
|
||||
* @ca_cert: File name for CA certificate in PEM or DER format
|
||||
* %NULL to allow all subjects
|
||||
@ -104,31 +211,28 @@ int tls_connection_ca_cert(void *tls_ctx, struct tls_connection *conn,
|
||||
int tls_global_ca_cert(void *tls_ctx, const char *ca_cert);
|
||||
|
||||
/**
|
||||
* tls_connection_ca_cert - set trusted CA certificate for TLS connection
|
||||
* tls_global_set_verify - Set global certificate verification options
|
||||
* @tls_ctx: TLS context data from tls_init()
|
||||
* @check_crl: 0 = do not verify CRLs, 1 = verify CRL for the user certificate,
|
||||
* 2 = verify CRL for all certificates
|
||||
*
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int tls_global_set_verify(void *tls_ctx, int check_crl);
|
||||
|
||||
/**
|
||||
* tls_connection_set_verify - Set certificate verification options
|
||||
* @tls_ctx: TLS context data from tls_init()
|
||||
* @conn: Connection context data from tls_connection_init()
|
||||
* @verify_peer: 1 = verify peer certificate
|
||||
* @subject_match: String to match in the subject of the peer certificate or
|
||||
* %NULL to allow all subjects
|
||||
*
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
|
||||
int verify_peer, const char *subject_match);
|
||||
int verify_peer);
|
||||
|
||||
/**
|
||||
* tls_connection_client_cert - set client certificate for TLS connection
|
||||
* @tls_ctx: TLS context data from tls_init()
|
||||
* @conn: Connection context data from tls_connection_init()
|
||||
* @client_cert: File name for client certificate in PEM or DER format
|
||||
*
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int tls_connection_client_cert(void *tls_ctx, struct tls_connection *conn,
|
||||
const char *client_cert);
|
||||
|
||||
/**
|
||||
* tls_global_client_cert - set client certificate for all TLS connections
|
||||
* tls_global_client_cert - Set client certificate for all TLS connections
|
||||
* @tls_ctx: TLS context data from tls_init()
|
||||
* @client_cert: File name for client certificate in PEM or DER format
|
||||
*
|
||||
@ -137,21 +241,7 @@ int tls_connection_client_cert(void *tls_ctx, struct tls_connection *conn,
|
||||
int tls_global_client_cert(void *tls_ctx, const char *client_cert);
|
||||
|
||||
/**
|
||||
* tls_connection_private_key - set private key for TLS connection
|
||||
* @tls_ctx: TLS context data from tls_init()
|
||||
* @conn: Connection context data from tls_connection_init()
|
||||
* @private_key: File name for client private key in PEM or DER format
|
||||
* @private_key_passwd: Passphrase for decrypted private key, %NULL if no
|
||||
* passphrase is used.
|
||||
*
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int tls_connection_private_key(void *tls_ctx, struct tls_connection *conn,
|
||||
const char *private_key,
|
||||
const char *private_key_passwd);
|
||||
|
||||
/**
|
||||
* tls_global_private_key - set private key for all TLS connections
|
||||
* tls_global_private_key - Set private key for all TLS connections
|
||||
* @tls_ctx: TLS context data from tls_init()
|
||||
* @private_key: File name for client private key in PEM or DER format
|
||||
* @private_key_passwd: Passphrase for decrypted private key, %NULL if no
|
||||
@ -163,18 +253,7 @@ int tls_global_private_key(void *tls_ctx, const char *private_key,
|
||||
const char *private_key_passwd);
|
||||
|
||||
/**
|
||||
* tls_connection_dh - set DH/DSA parameters for TLS connection
|
||||
* @tls_ctx: TLS context data from tls_init()
|
||||
* @conn: Connection context data from tls_connection_init()
|
||||
* @dh_file: File name for DH/DSA data in PEM format.
|
||||
*
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int tls_connection_dh(void *tls_ctx, struct tls_connection *conn,
|
||||
const char *dh_file);
|
||||
|
||||
/**
|
||||
* tls_connection_get_keys - get master key and random data from TLS connection
|
||||
* tls_connection_get_keys - Get master key and random data from TLS connection
|
||||
* @tls_ctx: TLS context data from tls_init()
|
||||
* @conn: Connection context data from tls_connection_init()
|
||||
* @keys: Structure of key/random data (filled on success)
|
||||
@ -185,23 +264,37 @@ int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
|
||||
struct tls_keys *keys);
|
||||
|
||||
/**
|
||||
* tls_connection_handshake - process TLS handshake (client side)
|
||||
* tls_connection_handshake - Process TLS handshake (client side)
|
||||
* @tls_ctx: TLS context data from tls_init()
|
||||
* @conn: Connection context data from tls_connection_init()
|
||||
* @in_data: Input data from TLS peer
|
||||
* @in_len: Input data length
|
||||
* @out_len: Length of the output buffer.
|
||||
*
|
||||
* Returns: pointer to output data, %NULL on failure
|
||||
* Returns: Pointer to output data, %NULL on failure
|
||||
*
|
||||
* Caller is responsible for freeing returned output data.
|
||||
*
|
||||
* This function is used during TLS handshake. The first call is done with
|
||||
* in_data == %NULL and the library is expected to return ClientHello packet.
|
||||
* This packet is then send to the server and a response from server is given
|
||||
* to TLS library by calling this function again with in_data pointing to the
|
||||
* TLS message from the server.
|
||||
*
|
||||
* If the TLS handshake fails, this function may return %NULL. However, if the
|
||||
* TLS library has a TLS alert to send out, that should be returned as the
|
||||
* output data. In this case, tls_connection_get_failed() must return failure
|
||||
* (> 0).
|
||||
*
|
||||
* tls_connection_established() should return 1 once the TLS handshake has been
|
||||
* completed successfully.
|
||||
*/
|
||||
u8 * tls_connection_handshake(void *tls_ctx, struct tls_connection *conn,
|
||||
const u8 *in_data, size_t in_len,
|
||||
size_t *out_len);
|
||||
|
||||
/**
|
||||
* tls_connection_servr_handshake - process TLS handshake (server side)
|
||||
* tls_connection_server_handshake - Process TLS handshake (server side)
|
||||
* @tls_ctx: TLS context data from tls_init()
|
||||
* @conn: Connection context data from tls_connection_init()
|
||||
* @in_data: Input data from TLS peer
|
||||
@ -218,37 +311,43 @@ u8 * tls_connection_server_handshake(void *tls_ctx,
|
||||
size_t *out_len);
|
||||
|
||||
/**
|
||||
* tls_connection_encrypt - encrypt data into TLS tunnel
|
||||
* tls_connection_encrypt - Encrypt data into TLS tunnel
|
||||
* @tls_ctx: TLS context data from tls_init()
|
||||
* @conn: Connection context data from tls_connection_init()
|
||||
* @in_data: Pointer to plaintext data to be encrypted
|
||||
* @in_len: Input buffer length
|
||||
* @out_data: Pointer to output buffer (encrypted TLS data)
|
||||
* @out_len: Maximum @out_data length
|
||||
* @out_len: Maximum out_data length
|
||||
*
|
||||
* Returns: Number of bytes written to @out_data, -1 on failure
|
||||
* Returns: Number of bytes written to out_data, -1 on failure
|
||||
*
|
||||
* This function is used after TLS handshake has been completed successfully to
|
||||
* send data in the encrypted tunnel.
|
||||
*/
|
||||
int tls_connection_encrypt(void *tls_ctx, struct tls_connection *conn,
|
||||
u8 *in_data, size_t in_len,
|
||||
const u8 *in_data, size_t in_len,
|
||||
u8 *out_data, size_t out_len);
|
||||
|
||||
/**
|
||||
* tls_connection_decrypt - decrypt data from TLS tunnel
|
||||
* tls_connection_decrypt - Decrypt data from TLS tunnel
|
||||
* @tls_ctx: TLS context data from tls_init()
|
||||
* @conn: Connection context data from tls_connection_init()
|
||||
* @in_data: Pointer to input buffer (encrypted TLS data)
|
||||
* @in_len: Input buffer length
|
||||
* @out_data: Pointer to output buffer (decrypted data from TLS tunnel)
|
||||
* @out_len: Maximum @out_data length
|
||||
* @out_len: Maximum out_data length
|
||||
*
|
||||
* Returns: Number of bytes written to @out_data, -1 on failure
|
||||
* Returns: Number of bytes written to out_data, -1 on failure
|
||||
*
|
||||
* This function is used after TLS handshake has been completed successfully to
|
||||
* receive data from the encrypted tunnel.
|
||||
*/
|
||||
int tls_connection_decrypt(void *tls_ctx, struct tls_connection *conn,
|
||||
u8 *in_data, size_t in_len,
|
||||
const u8 *in_data, size_t in_len,
|
||||
u8 *out_data, size_t out_len);
|
||||
|
||||
/**
|
||||
* tls_connection_resumed - was session resumption used
|
||||
* tls_connection_resumed - Was session resumption used
|
||||
* @tls_ctx: TLS context data from tls_init()
|
||||
* @conn: Connection context data from tls_connection_init()
|
||||
*
|
||||
@ -257,19 +356,19 @@ int tls_connection_decrypt(void *tls_ctx, struct tls_connection *conn,
|
||||
int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn);
|
||||
|
||||
/**
|
||||
* tls_connection_set_master_key - configure master secret for TLS connection
|
||||
* tls_connection_set_master_key - Configure master secret for TLS connection
|
||||
* @tls_ctx: TLS context data from tls_init()
|
||||
* @conn: Connection context data from tls_connection_init()
|
||||
* @key: TLS pre-master-secret
|
||||
* @key_len: length of @key in bytes
|
||||
* @key_len: length of key in bytes
|
||||
*
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int tls_connection_set_master_key(void *ssl_ctx, struct tls_connection *conn,
|
||||
int tls_connection_set_master_key(void *tls_ctx, struct tls_connection *conn,
|
||||
const u8 *key, size_t key_len);
|
||||
|
||||
/**
|
||||
* tls_connection_set_anon_dh - configure TLS connection to use anonymous DH
|
||||
* tls_connection_set_anon_dh - Configure TLS connection to use anonymous DH
|
||||
* @tls_ctx: TLS context data from tls_init()
|
||||
* @conn: Connection context data from tls_connection_init()
|
||||
*
|
||||
@ -278,22 +377,24 @@ int tls_connection_set_master_key(void *ssl_ctx, struct tls_connection *conn,
|
||||
* TODO: consider changing this to more generic routine for configuring allowed
|
||||
* ciphers
|
||||
*/
|
||||
int tls_connection_set_anon_dh(void *ssl_ctx, struct tls_connection *conn);
|
||||
int tls_connection_set_anon_dh(void *tls_ctx, struct tls_connection *conn);
|
||||
|
||||
/**
|
||||
* tls_get_cipher - get current cipher name
|
||||
* tls_get_cipher - Get current cipher name
|
||||
* @tls_ctx: TLS context data from tls_init()
|
||||
* @conn: Connection context data from tls_connection_init()
|
||||
* @buf: Buffer for the cipher name
|
||||
* @buflen: buf size
|
||||
*
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*
|
||||
* Get the name of the currently used cipher.
|
||||
*/
|
||||
int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
|
||||
int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
|
||||
char *buf, size_t buflen);
|
||||
|
||||
/**
|
||||
* tls_connection_enable_workaround - enable TLS workaround options
|
||||
* tls_connection_enable_workaround - Enable TLS workaround options
|
||||
* @tls_ctx: TLS context data from tls_init()
|
||||
* @conn: Connection context data from tls_connection_init()
|
||||
*
|
||||
@ -302,11 +403,61 @@ int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
|
||||
* This function is used to enable connection-specific workaround options for
|
||||
* buffer SSL/TLS implementations.
|
||||
*/
|
||||
int tls_connection_enable_workaround(void *ssl_ctx,
|
||||
int tls_connection_enable_workaround(void *tls_ctx,
|
||||
struct tls_connection *conn);
|
||||
|
||||
int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
|
||||
/**
|
||||
* tls_connection_client_hello_ext - Set TLS extension for ClientHello
|
||||
* @tls_ctx: TLS context data from tls_init()
|
||||
* @conn: Connection context data from tls_connection_init()
|
||||
* @ext_type: Extension type
|
||||
* @data: Extension payload (NULL to remove extension)
|
||||
* @data_len: Extension payload length
|
||||
*
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn,
|
||||
int ext_type, const u8 *data,
|
||||
size_t data_len);
|
||||
|
||||
/**
|
||||
* tls_connection_get_failed - Get connection failure status
|
||||
* @tls_ctx: TLS context data from tls_init()
|
||||
* @conn: Connection context data from tls_connection_init()
|
||||
*
|
||||
* Returns >0 if connection has failed, 0 if not.
|
||||
*/
|
||||
int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn);
|
||||
|
||||
/**
|
||||
* tls_connection_get_read_alerts - Get connection read alert status
|
||||
* @tls_ctx: TLS context data from tls_init()
|
||||
* @conn: Connection context data from tls_connection_init()
|
||||
*
|
||||
* Returns: Number of times a fatal read (remote end reported error) has
|
||||
* happened during this connection.
|
||||
*/
|
||||
int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn);
|
||||
|
||||
/**
|
||||
* tls_connection_get_write_alerts - Get connection write alert status
|
||||
* @tls_ctx: TLS context data from tls_init()
|
||||
* @conn: Connection context data from tls_connection_init()
|
||||
*
|
||||
* Returns: Number of times a fatal write (locally detected error) has happened
|
||||
* during this connection.
|
||||
*/
|
||||
int tls_connection_get_write_alerts(void *tls_ctx,
|
||||
struct tls_connection *conn);
|
||||
|
||||
/**
|
||||
* tls_connection_get_keyblock_size - Get TLS key_block size
|
||||
* @tls_ctx: TLS context data from tls_init()
|
||||
* @conn: Connection context data from tls_connection_init()
|
||||
* Returns: Size of the key_block for the negotiated cipher suite or -1 on
|
||||
* failure
|
||||
*/
|
||||
int tls_connection_get_keyblock_size(void *tls_ctx,
|
||||
struct tls_connection *conn);
|
||||
|
||||
#endif /* TLS_H */
|
||||
|
@ -12,7 +12,13 @@
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
void * tls_init(void)
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "tls.h"
|
||||
|
||||
void * tls_init(const struct tls_config *conf)
|
||||
{
|
||||
return (void *) 1;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
#ifndef VERSION_H
|
||||
#define VERSION_H
|
||||
|
||||
#define VERSION_STR "0.3.9"
|
||||
#define VERSION_STR "0.4.8"
|
||||
|
||||
#endif /* VERSION_H */
|
||||
|
@ -14,6 +14,8 @@ dump_file=/tmp/hostapd.dump
|
||||
ieee8021x=1
|
||||
eap_reauth_period=3600
|
||||
|
||||
use_pae_group_addr=1
|
||||
|
||||
|
||||
##### RADIUS configuration ####################################################
|
||||
# for IEEE 802.1X with external Authentication Server, IEEE 802.11
|
||||
|
@ -34,6 +34,8 @@
|
||||
#include "eloop.h"
|
||||
#include "sta_info.h"
|
||||
#include "l2_packet.h"
|
||||
#include "accounting.h"
|
||||
#include "hostap_common.h"
|
||||
|
||||
|
||||
static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx);
|
||||
@ -101,7 +103,7 @@ static const u8 RSN_KEY_DATA_PMKID[] = { 0x00, 0x0f, 0xac, 4 };
|
||||
* Authenticated Key Management Suite Count (2 octets, little endian)
|
||||
* (default: 1)
|
||||
* Authenticated Key Management Suite List (4 * n octets)
|
||||
* (default: unspec 802.1x)
|
||||
* (default: unspec 802.1X)
|
||||
* WPA Capabilities (2 octets, little endian) (default: 0)
|
||||
*/
|
||||
|
||||
@ -123,7 +125,7 @@ struct wpa_ie_hdr {
|
||||
* Authenticated Key Management Suite Count (2 octets, little endian)
|
||||
* (default: 1)
|
||||
* Authenticated Key Management Suite List (4 * n octets)
|
||||
* (default: unspec 802.1x)
|
||||
* (default: unspec 802.1X)
|
||||
* RSN Capabilities (2 octets, little endian) (default: 0)
|
||||
* PMKID Count (2 octets) (default: 0)
|
||||
* PMKID List (16 * n octets)
|
||||
@ -396,8 +398,8 @@ static void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx)
|
||||
|
||||
#ifdef CONFIG_RSN_PREAUTH
|
||||
|
||||
static void rsn_preauth_receive(void *ctx, unsigned char *src_addr,
|
||||
unsigned char *buf, size_t len)
|
||||
static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
|
||||
const u8 *buf, size_t len)
|
||||
{
|
||||
struct rsn_preauth_interface *piface = ctx;
|
||||
struct hostapd_data *hapd = piface->hapd;
|
||||
@ -480,13 +482,12 @@ static int rsn_preauth_iface_add(struct hostapd_data *hapd, const char *ifname)
|
||||
}
|
||||
|
||||
piface->l2 = l2_packet_init(piface->ifname, NULL, ETH_P_PREAUTH,
|
||||
rsn_preauth_receive, piface);
|
||||
rsn_preauth_receive, piface, 1);
|
||||
if (piface->l2 == NULL) {
|
||||
printf("Failed to open register layer 2 access to "
|
||||
"ETH_P_PREAUTH\n");
|
||||
goto fail2;
|
||||
}
|
||||
l2_packet_set_rx_l2_hdr(piface->l2, 1);
|
||||
|
||||
piface->next = hapd->preauth_iface;
|
||||
hapd->preauth_iface = piface;
|
||||
@ -551,6 +552,16 @@ static int rsn_preauth_iface_init(struct hostapd_data *hapd)
|
||||
}
|
||||
|
||||
|
||||
static void rsn_preauth_finished_cb(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
struct hostapd_data *hapd = eloop_ctx;
|
||||
struct sta_info *sta = timeout_ctx;
|
||||
wpa_printf(MSG_DEBUG, "RSN: Removing pre-authentication STA entry for "
|
||||
MACSTR, MAC2STR(sta->addr));
|
||||
ap_free_sta(hapd, sta);
|
||||
}
|
||||
|
||||
|
||||
void rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
int success)
|
||||
{
|
||||
@ -565,7 +576,11 @@ void rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
pmksa_cache_add(hapd, sta, key, dot11RSNAConfigPMKLifetime);
|
||||
}
|
||||
|
||||
ap_free_sta(hapd, sta);
|
||||
/*
|
||||
* Finish STA entry removal from timeout in order to avoid freeing
|
||||
* STA data before the caller has finished processing.
|
||||
*/
|
||||
eloop_register_timeout(0, 0, rsn_preauth_finished_cb, hapd, sta);
|
||||
}
|
||||
|
||||
|
||||
@ -598,8 +613,8 @@ void rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
ethhdr->h_proto = htons(ETH_P_PREAUTH);
|
||||
memcpy(ethhdr + 1, buf, len);
|
||||
|
||||
if (l2_packet_send(piface->l2, (u8 *) ethhdr, sizeof(*ethhdr) + len) <
|
||||
0) {
|
||||
if (l2_packet_send(piface->l2, sta->addr, ETH_P_PREAUTH, (u8 *) ethhdr,
|
||||
sizeof(*ethhdr) + len) < 0) {
|
||||
printf("Failed to send preauth packet using l2_packet_send\n");
|
||||
}
|
||||
free(ethhdr);
|
||||
@ -616,6 +631,10 @@ static inline void rsn_preauth_iface_deinit(struct hostapd_data *hapd)
|
||||
{
|
||||
}
|
||||
|
||||
static void rsn_preauth_finished_cb(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
}
|
||||
|
||||
void rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
int success)
|
||||
{
|
||||
@ -807,6 +826,16 @@ static void rsn_pmkid(const u8 *pmk, const u8 *aa, const u8 *spa, u8 *pmkid)
|
||||
static void pmksa_cache_set_expiration(struct hostapd_data *hapd);
|
||||
|
||||
|
||||
static void _pmksa_cache_free_entry(struct rsn_pmksa_cache *entry)
|
||||
{
|
||||
if (entry == NULL)
|
||||
return;
|
||||
free(entry->identity);
|
||||
ieee802_1x_free_radius_class(&entry->radius_class);
|
||||
free(entry);
|
||||
}
|
||||
|
||||
|
||||
static void pmksa_cache_free_entry(struct hostapd_data *hapd,
|
||||
struct rsn_pmksa_cache *entry)
|
||||
{
|
||||
@ -846,7 +875,7 @@ static void pmksa_cache_free_entry(struct hostapd_data *hapd,
|
||||
prev = pos;
|
||||
pos = pos->next;
|
||||
}
|
||||
free(entry);
|
||||
_pmksa_cache_free_entry(entry);
|
||||
}
|
||||
|
||||
|
||||
@ -882,6 +911,54 @@ static void pmksa_cache_set_expiration(struct hostapd_data *hapd)
|
||||
}
|
||||
|
||||
|
||||
static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache *entry,
|
||||
struct eapol_state_machine *eapol)
|
||||
{
|
||||
if (eapol == NULL)
|
||||
return;
|
||||
|
||||
if (eapol->identity) {
|
||||
entry->identity = malloc(eapol->identity_len);
|
||||
if (entry->identity) {
|
||||
entry->identity_len = eapol->identity_len;
|
||||
memcpy(entry->identity, eapol->identity,
|
||||
eapol->identity_len);
|
||||
}
|
||||
}
|
||||
|
||||
ieee802_1x_copy_radius_class(&entry->radius_class,
|
||||
&eapol->radius_class);
|
||||
}
|
||||
|
||||
|
||||
static void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache *entry,
|
||||
struct eapol_state_machine *eapol)
|
||||
{
|
||||
if (entry == NULL || eapol == NULL)
|
||||
return;
|
||||
|
||||
if (entry->identity) {
|
||||
free(eapol->identity);
|
||||
eapol->identity = malloc(entry->identity_len);
|
||||
if (eapol->identity) {
|
||||
eapol->identity_len = entry->identity_len;
|
||||
memcpy(eapol->identity, entry->identity,
|
||||
entry->identity_len);
|
||||
}
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "STA identity from PMKSA",
|
||||
eapol->identity, eapol->identity_len);
|
||||
}
|
||||
|
||||
ieee802_1x_free_radius_class(&eapol->radius_class);
|
||||
ieee802_1x_copy_radius_class(&eapol->radius_class,
|
||||
&entry->radius_class);
|
||||
if (eapol->radius_class.attr) {
|
||||
wpa_printf(MSG_DEBUG, "Copied %lu Class attribute(s) from "
|
||||
"PMKSA", (unsigned long) eapol->radius_class.count);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void pmksa_cache_add(struct hostapd_data *hapd, struct sta_info *sta, u8 *pmk,
|
||||
int session_timeout)
|
||||
{
|
||||
@ -903,6 +980,7 @@ void pmksa_cache_add(struct hostapd_data *hapd, struct sta_info *sta, u8 *pmk,
|
||||
entry->expiration += dot11RSNAConfigPMKLifetime;
|
||||
entry->akmp = WPA_KEY_MGMT_IEEE8021X;
|
||||
memcpy(entry->spa, sta->addr, ETH_ALEN);
|
||||
pmksa_cache_from_eapol_data(entry, sta->eapol_sm);
|
||||
|
||||
/* Replace an old entry for the same STA (if found) with the new entry
|
||||
*/
|
||||
@ -959,7 +1037,7 @@ static void pmksa_cache_free(struct hostapd_data *hapd)
|
||||
while (entry) {
|
||||
prev = entry;
|
||||
entry = entry->next;
|
||||
free(prev);
|
||||
_pmksa_cache_free_entry(prev);
|
||||
}
|
||||
eloop_cancel_timeout(pmksa_cache_expire, hapd, NULL);
|
||||
for (i = 0; i < PMKID_HASH_SIZE; i++)
|
||||
@ -999,7 +1077,7 @@ struct wpa_ie_data {
|
||||
};
|
||||
|
||||
|
||||
static int wpa_parse_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len,
|
||||
static int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
|
||||
struct wpa_ie_data *data)
|
||||
{
|
||||
struct wpa_ie_hdr *hdr;
|
||||
@ -1078,7 +1156,7 @@ static int wpa_parse_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len,
|
||||
}
|
||||
|
||||
|
||||
static int wpa_parse_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
|
||||
static int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
|
||||
struct wpa_ie_data *data)
|
||||
{
|
||||
struct rsn_ie_hdr *hdr;
|
||||
@ -1172,7 +1250,7 @@ static int wpa_parse_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
|
||||
|
||||
|
||||
int wpa_validate_wpa_ie(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
u8 *wpa_ie, size_t wpa_ie_len, int version)
|
||||
const u8 *wpa_ie, size_t wpa_ie_len, int version)
|
||||
{
|
||||
struct wpa_ie_data data;
|
||||
int ciphers, key_mgmt, res, i;
|
||||
@ -1372,6 +1450,7 @@ void wpa_free_station(struct sta_info *sta)
|
||||
|
||||
eloop_cancel_timeout(wpa_send_eapol_timeout, sm->hapd, sta);
|
||||
eloop_cancel_timeout(wpa_sm_call_step, sm->hapd, sta->wpa_sm);
|
||||
eloop_cancel_timeout(rsn_preauth_finished_cb, sm->hapd, sta);
|
||||
free(sm->last_rx_eapol_key);
|
||||
free(sm);
|
||||
sta->wpa_sm = NULL;
|
||||
@ -2088,6 +2167,7 @@ SM_STATE(WPA_PTK, INITPMK)
|
||||
if (sm->sta->pmksa) {
|
||||
wpa_printf(MSG_DEBUG, "WPA: PMK from PMKSA cache");
|
||||
memcpy(sm->PMK, sm->sta->pmksa->pmk, WPA_PMK_LEN);
|
||||
pmksa_cache_to_eapol_data(sm->sta->pmksa, sm->sta->eapol_sm);
|
||||
} else if ((key = ieee802_1x_get_key_crypt(sm->sta->eapol_sm, &len))) {
|
||||
wpa_printf(MSG_DEBUG, "WPA: PMK from EAPOL state machine "
|
||||
"(len=%lu)", (unsigned long) len);
|
||||
@ -2294,6 +2374,8 @@ SM_STATE(WPA_PTK, PTKINITDONE)
|
||||
HOSTAPD_LEVEL_INFO, "pairwise key handshake completed "
|
||||
"(%s)",
|
||||
sm->sta->wpa == WPA_VERSION_WPA ? "WPA" : "RSN");
|
||||
if (sm->sta->wpa_key_mgmt == WPA_KEY_MGMT_PSK)
|
||||
accounting_sta_start(sm->hapd, sm->sta);
|
||||
}
|
||||
|
||||
|
||||
|
@ -16,6 +16,9 @@ struct rsn_pmksa_cache {
|
||||
time_t expiration;
|
||||
int akmp; /* WPA_KEY_MGMT_* */
|
||||
u8 spa[ETH_ALEN];
|
||||
u8 *identity;
|
||||
size_t identity_len;
|
||||
struct radius_class_data radius_class;
|
||||
};
|
||||
|
||||
struct rsn_preauth_interface {
|
||||
@ -167,7 +170,7 @@ enum {
|
||||
};
|
||||
|
||||
int wpa_validate_wpa_ie(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
u8 *wpa_ie, size_t wpa_ie_len, int version);
|
||||
const u8 *wpa_ie, size_t wpa_ie_len, int version);
|
||||
void wpa_new_station(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
void wpa_free_station(struct sta_info *sta);
|
||||
void wpa_receive(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
|
239
contrib/hostapd/wpa_ctrl.c
Normal file
239
contrib/hostapd/wpa_ctrl.c
Normal file
@ -0,0 +1,239 @@
|
||||
/*
|
||||
* wpa_supplicant/hostapd control interface library
|
||||
* Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#ifndef CONFIG_NATIVE_WINDOWS
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/un.h>
|
||||
#endif /* CONFIG_NATIVE_WINDOWS */
|
||||
|
||||
#include "wpa_ctrl.h"
|
||||
#ifdef CONFIG_NATIVE_WINDOWS
|
||||
#include "common.h"
|
||||
#endif /* CONFIG_NATIVE_WINDOWS */
|
||||
|
||||
|
||||
/**
|
||||
* struct wpa_ctrl - Internal structure for control interface library
|
||||
*
|
||||
* This structure is used by the wpa_supplicant/hostapd control interface
|
||||
* library to store internal data. Programs using the library should not touch
|
||||
* this data directly. They can only use the pointer to the data structure as
|
||||
* an identifier for the control interface connection and use this as one of
|
||||
* the arguments for most of the control interface library functions.
|
||||
*/
|
||||
struct wpa_ctrl {
|
||||
int s;
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP
|
||||
struct sockaddr_in local;
|
||||
struct sockaddr_in dest;
|
||||
#else /* CONFIG_CTRL_IFACE_UDP */
|
||||
struct sockaddr_un local;
|
||||
struct sockaddr_un dest;
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP */
|
||||
};
|
||||
|
||||
|
||||
struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
|
||||
{
|
||||
struct wpa_ctrl *ctrl;
|
||||
#ifndef CONFIG_CTRL_IFACE_UDP
|
||||
static int counter = 0;
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP */
|
||||
|
||||
ctrl = malloc(sizeof(*ctrl));
|
||||
if (ctrl == NULL)
|
||||
return NULL;
|
||||
memset(ctrl, 0, sizeof(*ctrl));
|
||||
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP
|
||||
ctrl->s = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (ctrl->s < 0) {
|
||||
perror("socket");
|
||||
free(ctrl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctrl->local.sin_family = AF_INET;
|
||||
ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1);
|
||||
if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
|
||||
sizeof(ctrl->local)) < 0) {
|
||||
close(ctrl->s);
|
||||
free(ctrl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctrl->dest.sin_family = AF_INET;
|
||||
ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1);
|
||||
ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT);
|
||||
if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
|
||||
sizeof(ctrl->dest)) < 0) {
|
||||
perror("connect");
|
||||
close(ctrl->s);
|
||||
free(ctrl);
|
||||
return NULL;
|
||||
}
|
||||
#else /* CONFIG_CTRL_IFACE_UDP */
|
||||
ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
|
||||
if (ctrl->s < 0) {
|
||||
free(ctrl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctrl->local.sun_family = AF_UNIX;
|
||||
snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path),
|
||||
"/tmp/wpa_ctrl_%d-%d", getpid(), counter++);
|
||||
if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
|
||||
sizeof(ctrl->local)) < 0) {
|
||||
close(ctrl->s);
|
||||
free(ctrl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctrl->dest.sun_family = AF_UNIX;
|
||||
snprintf(ctrl->dest.sun_path, sizeof(ctrl->dest.sun_path), "%s",
|
||||
ctrl_path);
|
||||
if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
|
||||
sizeof(ctrl->dest)) < 0) {
|
||||
close(ctrl->s);
|
||||
unlink(ctrl->local.sun_path);
|
||||
free(ctrl);
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP */
|
||||
|
||||
return ctrl;
|
||||
}
|
||||
|
||||
|
||||
void wpa_ctrl_close(struct wpa_ctrl *ctrl)
|
||||
{
|
||||
#ifndef CONFIG_CTRL_IFACE_UDP
|
||||
unlink(ctrl->local.sun_path);
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP */
|
||||
close(ctrl->s);
|
||||
free(ctrl);
|
||||
}
|
||||
|
||||
|
||||
int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
|
||||
char *reply, size_t *reply_len,
|
||||
void (*msg_cb)(char *msg, size_t len))
|
||||
{
|
||||
struct timeval tv;
|
||||
int res;
|
||||
fd_set rfds;
|
||||
|
||||
if (send(ctrl->s, cmd, cmd_len, 0) < 0)
|
||||
return -1;
|
||||
|
||||
for (;;) {
|
||||
tv.tv_sec = 2;
|
||||
tv.tv_usec = 0;
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(ctrl->s, &rfds);
|
||||
res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
|
||||
if (FD_ISSET(ctrl->s, &rfds)) {
|
||||
res = recv(ctrl->s, reply, *reply_len, 0);
|
||||
if (res < 0)
|
||||
return res;
|
||||
if (res > 0 && reply[0] == '<') {
|
||||
/* This is an unsolicited message from
|
||||
* wpa_supplicant, not the reply to the
|
||||
* request. Use msg_cb to report this to the
|
||||
* caller. */
|
||||
if (msg_cb) {
|
||||
/* Make sure the message is nul
|
||||
* terminated. */
|
||||
if ((size_t) res == *reply_len)
|
||||
res = (*reply_len) - 1;
|
||||
reply[res] = '\0';
|
||||
msg_cb(reply, res);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
*reply_len = res;
|
||||
break;
|
||||
} else {
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach)
|
||||
{
|
||||
char buf[10];
|
||||
int ret;
|
||||
size_t len = 10;
|
||||
|
||||
ret = wpa_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6,
|
||||
buf, &len, NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (len == 3 && memcmp(buf, "OK\n", 3) == 0)
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int wpa_ctrl_attach(struct wpa_ctrl *ctrl)
|
||||
{
|
||||
return wpa_ctrl_attach_helper(ctrl, 1);
|
||||
}
|
||||
|
||||
|
||||
int wpa_ctrl_detach(struct wpa_ctrl *ctrl)
|
||||
{
|
||||
return wpa_ctrl_attach_helper(ctrl, 0);
|
||||
}
|
||||
|
||||
|
||||
int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = recv(ctrl->s, reply, *reply_len, 0);
|
||||
if (res < 0)
|
||||
return res;
|
||||
*reply_len = res;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
|
||||
{
|
||||
struct timeval tv;
|
||||
int res;
|
||||
fd_set rfds;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(ctrl->s, &rfds);
|
||||
res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
|
||||
return FD_ISSET(ctrl->s, &rfds);
|
||||
}
|
||||
|
||||
|
||||
int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
|
||||
{
|
||||
return ctrl->s;
|
||||
}
|
185
contrib/hostapd/wpa_ctrl.h
Normal file
185
contrib/hostapd/wpa_ctrl.h
Normal file
@ -0,0 +1,185 @@
|
||||
/*
|
||||
* wpa_supplicant/hostapd control interface library
|
||||
* Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#ifndef WPA_CTRL_H
|
||||
#define WPA_CTRL_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* wpa_supplicant control interface - fixed message prefixes */
|
||||
|
||||
/** Interactive request for identity/password/pin */
|
||||
#define WPA_CTRL_REQ "CTRL-REQ-"
|
||||
|
||||
/** Response to identity/password/pin request */
|
||||
#define WPA_CTRL_RSP "CTRL-RSP-"
|
||||
|
||||
/* Event messages with fixed prefix */
|
||||
/** Authentication completed successfully and data connection enabled */
|
||||
#define WPA_EVENT_CONNECTED "CTRL-EVENT-CONNECTED "
|
||||
/** Disconnected, data connection is not available */
|
||||
#define WPA_EVENT_DISCONNECTED "CTRL-EVENT-DISCONNECTED "
|
||||
/** wpa_supplicant is exiting */
|
||||
#define WPA_EVENT_TERMINATING "CTRL-EVENT-TERMINATING "
|
||||
/** Password change was completed successfully */
|
||||
#define WPA_EVENT_PASSWORD_CHANGED "CTRL-EVENT-PASSWORD-CHANGED "
|
||||
/** EAP-Request/Notification received */
|
||||
#define WPA_EVENT_EAP_NOTIFICATION "CTRL-EVENT-EAP-NOTIFICATION "
|
||||
/** EAP authentication started (EAP-Request/Identity received) */
|
||||
#define WPA_EVENT_EAP_STARTED "CTRL-EVENT-EAP-STARTED "
|
||||
/** EAP method selected */
|
||||
#define WPA_EVENT_EAP_METHOD "CTRL-EVENT-EAP-METHOD "
|
||||
/** EAP authentication completed successfully */
|
||||
#define WPA_EVENT_EAP_SUCCESS "CTRL-EVENT-EAP-SUCCESS "
|
||||
/** EAP authentication failed (EAP-Failure received) */
|
||||
#define WPA_EVENT_EAP_FAILURE "CTRL-EVENT-EAP-FAILURE "
|
||||
|
||||
|
||||
/* wpa_supplicant/hostapd control interface access */
|
||||
|
||||
/**
|
||||
* wpa_ctrl_open - Open a control interface to wpa_supplicant/hostapd
|
||||
* @ctrl_path: Path for UNIX domain sockets; ignored if UDP sockets are used.
|
||||
* Returns: Pointer to abstract control interface data or %NULL on failure
|
||||
*
|
||||
* This function is used to open a control interface to wpa_supplicant/hostapd.
|
||||
* ctrl_path is usually /var/run/wpa_supplicant or /var/run/hostapd. This path
|
||||
* is configured in wpa_supplicant/hostapd and other programs using the control
|
||||
* interface need to use matching path configuration.
|
||||
*/
|
||||
struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path);
|
||||
|
||||
|
||||
/**
|
||||
* wpa_ctrl_close - Close a control interface to wpa_supplicant/hostapd
|
||||
* @ctrl: Control interface data from wpa_ctrl_open()
|
||||
*
|
||||
* This function is used to close a control interface.
|
||||
*/
|
||||
void wpa_ctrl_close(struct wpa_ctrl *ctrl);
|
||||
|
||||
|
||||
/**
|
||||
* wpa_ctrl_request - Send a command to wpa_supplicant/hostapd
|
||||
* @ctrl: Control interface data from wpa_ctrl_open()
|
||||
* @cmd: Command; usually, ASCII text, e.g., "PING"
|
||||
* @cmd_len: Length of the cmd in bytes
|
||||
* @reply: Buffer for the response
|
||||
* @reply_len: Reply buffer length
|
||||
* @msg_cb: Callback function for unsolicited messages or %NULL if not used
|
||||
* Returns: 0 on success, -1 on error (send or receive failed), -2 on timeout
|
||||
*
|
||||
* This function is used to send commands to wpa_supplicant/hostapd. Received
|
||||
* response will be written to reply and reply_len is set to the actual length
|
||||
* of the reply. This function will block for up to two seconds while waiting
|
||||
* for the reply. If unsolicited messages are received, the blocking time may
|
||||
* be longer.
|
||||
*
|
||||
* msg_cb can be used to register a callback function that will be called for
|
||||
* unsolicited messages received while waiting for the command response. These
|
||||
* messages may be received if wpa_ctrl_request() is called at the same time as
|
||||
* wpa_supplicant/hostapd is sending such a message. This can happen only if
|
||||
* the program has used wpa_ctrl_attach() to register itself as a monitor for
|
||||
* event messages. Alternatively to msg_cb, programs can register two control
|
||||
* interface connections and use one of them for commands and the other one for
|
||||
* receiving event messages, in other words, call wpa_ctrl_attach() only for
|
||||
* the control interface connection that will be used for event messages.
|
||||
*/
|
||||
int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
|
||||
char *reply, size_t *reply_len,
|
||||
void (*msg_cb)(char *msg, size_t len));
|
||||
|
||||
|
||||
/**
|
||||
* wpa_ctrl_attach - Register as an event monitor for the control interface
|
||||
* @ctrl: Control interface data from wpa_ctrl_open()
|
||||
* Returns: 0 on success, -1 on failure, -2 on timeout
|
||||
*
|
||||
* This function registers the control interface connection as a monitor for
|
||||
* wpa_supplicant/hostapd events. After a success wpa_ctrl_attach() call, the
|
||||
* control interface connection starts receiving event messages that can be
|
||||
* read with wpa_ctrl_recv().
|
||||
*/
|
||||
int wpa_ctrl_attach(struct wpa_ctrl *ctrl);
|
||||
|
||||
|
||||
/**
|
||||
* wpa_ctrl_detach - Unregister event monitor from the control interface
|
||||
* @ctrl: Control interface data from wpa_ctrl_open()
|
||||
* Returns: 0 on success, -1 on failure, -2 on timeout
|
||||
*
|
||||
* This function unregisters the control interface connection as a monitor for
|
||||
* wpa_supplicant/hostapd events, i.e., cancels the registration done with
|
||||
* wpa_ctrl_attach().
|
||||
*/
|
||||
int wpa_ctrl_detach(struct wpa_ctrl *ctrl);
|
||||
|
||||
|
||||
/**
|
||||
* wpa_ctrl_recv - Receive a pending control interface message
|
||||
* @ctrl: Control interface data from wpa_ctrl_open()
|
||||
* @reply: Buffer for the message data
|
||||
* @reply_len: Length of the reply buffer
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*
|
||||
* This function will receive a pending control interface message. This
|
||||
* function will block if no messages are available. The received response will
|
||||
* be written to reply and reply_len is set to the actual length of the reply.
|
||||
* wpa_ctrl_recv() is only used for event messages, i.e., wpa_ctrl_attach()
|
||||
* must have been used to register the control interface as an event monitor.
|
||||
*/
|
||||
int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len);
|
||||
|
||||
|
||||
/**
|
||||
* wpa_ctrl_pending - Check whether there are pending event messages
|
||||
* @ctrl: Control interface data from wpa_ctrl_open()
|
||||
* Returns: Non-zero if there are pending messages
|
||||
*
|
||||
* This function will check whether there are any pending control interface
|
||||
* message available to be received with wpa_ctrl_recv(). wpa_ctrl_pending() is
|
||||
* only used for event messages, i.e., wpa_ctrl_attach() must have been used to
|
||||
* register the control interface as an event monitor.
|
||||
*/
|
||||
int wpa_ctrl_pending(struct wpa_ctrl *ctrl);
|
||||
|
||||
|
||||
/**
|
||||
* wpa_ctrl_get_fd - Get file descriptor used by the control interface
|
||||
* @ctrl: Control interface data from wpa_ctrl_open()
|
||||
* Returns: File descriptor used for the connection
|
||||
*
|
||||
* This function can be used to get the file descriptor that is used for the
|
||||
* control interface connection. The returned value can be used, e.g., with
|
||||
* select() while waiting for multiple events.
|
||||
*
|
||||
* The returned file descriptor must not be used directly for sending or
|
||||
* receiving packets; instead, the library functions wpa_ctrl_request() and
|
||||
* wpa_ctrl_recv() must be used for this.
|
||||
*/
|
||||
int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl);
|
||||
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP
|
||||
#define WPA_CTRL_IFACE_PORT 9877
|
||||
#define WPA_GLOBAL_CTRL_IFACE_PORT 9878
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* WPA_CTRL_H */
|
Loading…
Reference in New Issue
Block a user