Import of hostapd 0.4.8

This commit is contained in:
Sam Leffler 2006-03-07 05:47:04 +00:00
parent fd7895c8dd
commit 89f5e593c0
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/vendor/hostapd/dist/; revision=156373
88 changed files with 7731 additions and 1694 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
}

View File

@ -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).
*/
};

View File

@ -0,0 +1,14 @@
#ifndef CONFIG_TYPES_H
#define CONFIG_TYPES_H
struct hostapd_ip_addr {
union {
struct in_addr v4;
#ifdef CONFIG_IPV6
struct in6_addr v6;
#endif /* CONFIG_IPV6 */
} u;
int af; /* AF_INET / AF_INET6 */
};
#endif /* CONFIG_TYPES_H */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 = &eth;
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,
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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
View 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,
};

View File

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

View File

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

View File

@ -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
View 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,
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
}
}

View File

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

View File

@ -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,
};

View File

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

View File

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

View File

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

View File

@ -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
View 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).

View File

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

View File

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

View File

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

View File

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

View 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).

View File

@ -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");

View File

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

View File

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

View File

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

View File

@ -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);
}

View File

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

View File

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

View File

@ -0,0 +1,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/

View 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);

View 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
}
}

View File

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

View File

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

View File

@ -9,6 +9,7 @@ struct radius_server_conf {
void *hostapd_conf;
void *eap_sim_db_priv;
void *ssl_ctx;
int ipv6;
};

View File

@ -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);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
}

View File

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