aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSam Leffler <sam@FreeBSD.org>2006-03-07 05:47:04 +0000
committerSam Leffler <sam@FreeBSD.org>2006-03-07 05:47:04 +0000
commit89f5e593c04599b48d6b59a8c4841676a988ac4f (patch)
treedacc7977efdefefb8b105113edeb5215c0e01234
parentfd7895c8ddcea473b398cad289b9f26e9612fc48 (diff)
downloadsrc-89f5e593c04599b48d6b59a8c4841676a988ac4f.tar.gz
src-89f5e593c04599b48d6b59a8c4841676a988ac4f.zip
Import of hostapd 0.4.8
Notes
Notes: svn path=/vendor/hostapd/dist/; revision=156373
-rw-r--r--contrib/hostapd/ChangeLog96
-rw-r--r--contrib/hostapd/Makefile36
-rw-r--r--contrib/hostapd/README8
-rw-r--r--contrib/hostapd/accounting.c40
-rw-r--r--contrib/hostapd/aes.c555
-rw-r--r--contrib/hostapd/aes_wrap.c231
-rw-r--r--contrib/hostapd/aes_wrap.h41
-rw-r--r--contrib/hostapd/common.c73
-rw-r--r--contrib/hostapd/common.h88
-rw-r--r--contrib/hostapd/config.c196
-rw-r--r--contrib/hostapd/config.h56
-rw-r--r--contrib/hostapd/config_types.h14
-rw-r--r--contrib/hostapd/crypto.c109
-rw-r--r--contrib/hostapd/crypto.h117
-rw-r--r--contrib/hostapd/ctrl_iface.c6
-rw-r--r--contrib/hostapd/defconfig27
-rw-r--r--contrib/hostapd/defs.h121
-rw-r--r--contrib/hostapd/driver.h15
-rw-r--r--contrib/hostapd/driver_test.c426
-rw-r--r--contrib/hostapd/driver_wired.c9
-rw-r--r--contrib/hostapd/eap.c35
-rw-r--r--contrib/hostapd/eap.h12
-rw-r--r--contrib/hostapd/eap_defs.h31
-rw-r--r--contrib/hostapd/eap_i.h2
-rw-r--r--contrib/hostapd/eap_identity.c15
-rw-r--r--contrib/hostapd/eap_md5.c16
-rw-r--r--contrib/hostapd/eap_pax.c519
-rw-r--r--contrib/hostapd/eap_pax_common.c152
-rw-r--r--contrib/hostapd/eap_pax_common.h84
-rw-r--r--contrib/hostapd/eap_peap.c6
-rw-r--r--contrib/hostapd/eap_psk.c458
-rw-r--r--contrib/hostapd/eap_psk_common.c57
-rw-r--r--contrib/hostapd/eap_psk_common.h92
-rw-r--r--contrib/hostapd/eap_sim.c2
-rw-r--r--contrib/hostapd/eap_sim_common.c78
-rw-r--r--contrib/hostapd/eap_sim_common.h35
-rw-r--r--contrib/hostapd/eap_sim_db.c1
-rw-r--r--contrib/hostapd/eap_tls.c7
-rw-r--r--contrib/hostapd/eap_tls_common.c10
-rw-r--r--contrib/hostapd/eap_ttls.c22
-rw-r--r--contrib/hostapd/eap_ttls.h14
-rw-r--r--contrib/hostapd/eapol_sm.c160
-rw-r--r--contrib/hostapd/eapol_sm.h13
-rw-r--r--contrib/hostapd/eloop.c21
-rw-r--r--contrib/hostapd/eloop.h137
-rw-r--r--contrib/hostapd/hostap_common.h1
-rw-r--r--contrib/hostapd/hostapd.856
-rw-r--r--contrib/hostapd/hostapd.c78
-rw-r--r--contrib/hostapd/hostapd.conf98
-rw-r--r--contrib/hostapd/hostapd.eap_user6
-rw-r--r--contrib/hostapd/hostapd.h23
-rw-r--r--contrib/hostapd/hostapd_cli.183
-rw-r--r--contrib/hostapd/hostapd_cli.c131
-rw-r--r--contrib/hostapd/iapp.c1
-rw-r--r--contrib/hostapd/ieee802_11.c19
-rw-r--r--contrib/hostapd/ieee802_11_auth.c25
-rw-r--r--contrib/hostapd/ieee802_1x.c221
-rw-r--r--contrib/hostapd/ieee802_1x.h12
-rw-r--r--contrib/hostapd/l2_packet.h109
-rw-r--r--contrib/hostapd/logwatch/README9
-rwxr-xr-xcontrib/hostapd/logwatch/hostapd65
-rw-r--r--contrib/hostapd/logwatch/hostapd.conf10
-rw-r--r--contrib/hostapd/madwifi.conf107
-rw-r--r--contrib/hostapd/md5.c146
-rw-r--r--contrib/hostapd/md5.h46
-rw-r--r--contrib/hostapd/ms_funcs.c200
-rw-r--r--contrib/hostapd/ms_funcs.h51
-rw-r--r--contrib/hostapd/radius.c219
-rw-r--r--contrib/hostapd/radius.h18
-rw-r--r--contrib/hostapd/radius_client.c375
-rw-r--r--contrib/hostapd/radius_client.h48
-rw-r--r--contrib/hostapd/radius_server.c203
-rw-r--r--contrib/hostapd/radius_server.h1
-rw-r--r--contrib/hostapd/rc4.c32
-rw-r--r--contrib/hostapd/rc4.h19
-rw-r--r--contrib/hostapd/sha1.c202
-rw-r--r--contrib/hostapd/sha1.h45
-rw-r--r--contrib/hostapd/sta_info.c7
-rw-r--r--contrib/hostapd/sta_info.h4
-rw-r--r--contrib/hostapd/tls.h317
-rw-r--r--contrib/hostapd/tls_none.c8
-rw-r--r--contrib/hostapd/tls_openssl.c1614
-rw-r--r--contrib/hostapd/version.h2
-rw-r--r--contrib/hostapd/wired.conf2
-rw-r--r--contrib/hostapd/wpa.c110
-rw-r--r--contrib/hostapd/wpa.h5
-rw-r--r--contrib/hostapd/wpa_ctrl.c239
-rw-r--r--contrib/hostapd/wpa_ctrl.h185
88 files changed, 7716 insertions, 1679 deletions
diff --git a/contrib/hostapd/ChangeLog b/contrib/hostapd/ChangeLog
index 9d15f75b2ef6..f7bd4102d094 100644
--- a/contrib/hostapd/ChangeLog
+++ b/contrib/hostapd/ChangeLog
@@ -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)
diff --git a/contrib/hostapd/Makefile b/contrib/hostapd/Makefile
index 0ea99c923359..276baeeed8c5 100644
--- a/contrib/hostapd/Makefile
+++ b/contrib/hostapd/Makefile
@@ -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
diff --git a/contrib/hostapd/README b/contrib/hostapd/README
index 18fc1793cac8..d5354624b5da 100644
--- a/contrib/hostapd/README
+++ b/contrib/hostapd/README
@@ -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.
diff --git a/contrib/hostapd/accounting.c b/contrib/hostapd/accounting.c
index 188f8598b0b1..5ee3d750f9f2 100644
--- a/contrib/hostapd/accounting.c
+++ b/contrib/hostapd/accounting.c
@@ -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
diff --git a/contrib/hostapd/aes.c b/contrib/hostapd/aes.c
index eabebd074653..ce94778dd62e 100644
--- a/contrib/hostapd/aes.c
+++ b/contrib/hostapd/aes.c
@@ -1,8 +1,15 @@
/*
+ * AES (Rijndael) cipher
+ *
* Modifications to public domain implementation:
* - support only 128-bit keys
* - cleanup
- * Copyright (c) 2003-2004, Jouni Malinen <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);
+}
diff --git a/contrib/hostapd/aes_wrap.c b/contrib/hostapd/aes_wrap.c
index dbcc136517e7..a5925ca2ec47 100644
--- a/contrib/hostapd/aes_wrap.c
+++ b/contrib/hostapd/aes_wrap.c
@@ -1,10 +1,13 @@
/*
- * AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
- * One-Key CBC MAC (OMAC1) hash with AES-128
- * AES-128 CTR mode encryption
- * AES-128 EAX mode encryption/decryption
- * AES-128 CBC
- * Copyright (c) 2003-2004, Jouni Malinen <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++;
diff --git a/contrib/hostapd/aes_wrap.h b/contrib/hostapd/aes_wrap.h
index 70e83ea09d73..cb1a53967761 100644
--- a/contrib/hostapd/aes_wrap.h
+++ b/contrib/hostapd/aes_wrap.h
@@ -1,21 +1,42 @@
+/*
+ * AES-based functions
+ *
+ * - AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
+ * - One-Key CBC MAC (OMAC1) hash with AES-128
+ * - AES-128 CTR mode encryption
+ * - AES-128 EAX mode encryption/decryption
+ * - AES-128 CBC
+ *
+ * Copyright (c) 2003-2005, Jouni Malinen <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 */
diff --git a/contrib/hostapd/common.c b/contrib/hostapd/common.c
index 071ffe87c1d1..4b756d8f9292 100644
--- a/contrib/hostapd/common.c
+++ b/contrib/hostapd/common.c
@@ -1,6 +1,5 @@
/*
- * Host AP (software wireless LAN access point) user space daemon for
- * Host AP kernel driver / common helper functions, etc.
+ * wpa_supplicant/hostapd / common helper functions, etc.
* Copyright (c) 2002-2005, Jouni Malinen <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
diff --git a/contrib/hostapd/common.h b/contrib/hostapd/common.h
index 0f154e901bff..4bece7f6ecd9 100644
--- a/contrib/hostapd/common.h
+++ b/contrib/hostapd/common.h
@@ -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 { \
diff --git a/contrib/hostapd/config.c b/contrib/hostapd/config.c
index 02ecd7966cdd..34e2256aa6b5 100644
--- a/contrib/hostapd/config.c
+++ b/contrib/hostapd/config.c
@@ -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;
+ 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;
}
- 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);
}
diff --git a/contrib/hostapd/config.h b/contrib/hostapd/config.h
index 0ffc3adb4366..c56f4e7bf241 100644
--- a/contrib/hostapd/config.h
+++ b/contrib/hostapd/config.h
@@ -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;
-
- int radius_retry_primary_interval;
- int radius_acct_interim_interval;
+ struct hostapd_radius_servers *radius;
+
#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).
+ */
};
diff --git a/contrib/hostapd/config_types.h b/contrib/hostapd/config_types.h
new file mode 100644
index 000000000000..12b57cb4acf1
--- /dev/null
+++ b/contrib/hostapd/config_types.h
@@ -0,0 +1,14 @@
+#ifndef CONFIG_TYPES_H
+#define CONFIG_TYPES_H
+
+struct hostapd_ip_addr {
+ union {
+ struct in_addr v4;
+#ifdef CONFIG_IPV6
+ struct in6_addr v6;
+#endif /* CONFIG_IPV6 */
+ } u;
+ int af; /* AF_INET / AF_INET6 */
+};
+
+#endif /* CONFIG_TYPES_H */
diff --git a/contrib/hostapd/crypto.c b/contrib/hostapd/crypto.c
index cd278e0fae59..b4c81892c66e 100644
--- a/contrib/hostapd/crypto.c
+++ b/contrib/hostapd/crypto.c
@@ -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 */
diff --git a/contrib/hostapd/crypto.h b/contrib/hostapd/crypto.h
index 3e1a0e5cd3f8..e664861afe71 100644
--- a/contrib/hostapd/crypto.h
+++ b/contrib/hostapd/crypto.h
@@ -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 */
diff --git a/contrib/hostapd/ctrl_iface.c b/contrib/hostapd/ctrl_iface.c
index 9ed109bd5814..ff730d4a95d3 100644
--- a/contrib/hostapd/ctrl_iface.c
+++ b/contrib/hostapd/ctrl_iface.c
@@ -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;
}
diff --git a/contrib/hostapd/defconfig b/contrib/hostapd/defconfig
index b27c0374da5e..e8f4e4fc53ec 100644
--- a/contrib/hostapd/defconfig
+++ b/contrib/hostapd/defconfig
@@ -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
diff --git a/contrib/hostapd/defs.h b/contrib/hostapd/defs.h
index a5a515c552f5..6f9881d71d03 100644
--- a/contrib/hostapd/defs.h
+++ b/contrib/hostapd/defs.h
@@ -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 */
diff --git a/contrib/hostapd/driver.h b/contrib/hostapd/driver.h
index 365deda48a2a..ed9ecbfdbc8c 100644
--- a/contrib/hostapd/driver.h
+++ b/contrib/hostapd/driver.h
@@ -11,14 +11,14 @@ struct driver_ops {
void (*wireless_event_deinit)(void *priv);
/**
- * set_8021x - enable/disable 802.1x support
+ * set_8021x - enable/disable IEEE 802.1X support
* @priv: driver private data
* @enabled: 1 = enable, 0 = disable
*
* Returns: 0 on success, -1 on failure
*
- * Configure the kernel driver to enable/disable 802.1x support.
- * This may be an empty function if 802.1x support is always enabled.
+ * Configure the kernel driver to enable/disable 802.1X support.
+ * This may be an empty function if 802.1X support is always enabled.
*/
int (*set_ieee8021x)(void *priv, int enabled);
@@ -49,6 +49,7 @@ struct driver_ops {
int (*sta_remove)(void *priv, u8 *addr);
int (*get_ssid)(void *priv, u8 *buf, int len);
int (*set_ssid)(void *priv, u8 *buf, int len);
+ int (*set_countermeasures)(void *priv, int enabled);
int (*send_mgmt_frame)(void *priv, const void *msg, size_t len,
int flags);
int (*set_assoc_ap)(void *priv, u8 *addr);
@@ -228,6 +229,14 @@ hostapd_set_assoc_ap(struct hostapd_data *hapd, u8 *addr)
return hapd->driver->set_assoc_ap(hapd->driver, addr);
}
+static inline int
+hostapd_set_countermeasures(struct hostapd_data *hapd, int enabled)
+{
+ if (hapd->driver == NULL || hapd->driver->set_countermeasures == NULL)
+ return 0;
+ return hapd->driver->set_countermeasures(hapd->driver, enabled);
+}
+
static inline int
hostapd_sta_add(struct hostapd_data *hapd, u8 *addr, u16 aid, u16 capability,
u8 tx_supp_rates)
diff --git a/contrib/hostapd/driver_test.c b/contrib/hostapd/driver_test.c
index 612d1dcc5a24..6af9af256262 100644
--- a/contrib/hostapd/driver_test.c
+++ b/contrib/hostapd/driver_test.c
@@ -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,
};
diff --git a/contrib/hostapd/driver_wired.c b/contrib/hostapd/driver_wired.c
index 3e21268514f8..6ef6b19f53ff 100644
--- a/contrib/hostapd/driver_wired.c
+++ b/contrib/hostapd/driver_wired.c
@@ -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;
diff --git a/contrib/hostapd/eap.c b/contrib/hostapd/eap.c
index 7a21c802e5a4..a20147e79e78 100644
--- a/contrib/hostapd/eap.c
+++ b/contrib/hostapd/eap.c
@@ -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;
+}
diff --git a/contrib/hostapd/eap.h b/contrib/hostapd/eap.h
index 01f47dad12e4..c5c62eb57c72 100644
--- a/contrib/hostapd/eap.h
+++ b/contrib/hostapd/eap.h
@@ -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 */
diff --git a/contrib/hostapd/eap_defs.h b/contrib/hostapd/eap_defs.h
index effe665f0919..9cd44905153d 100644
--- a/contrib/hostapd/eap_defs.h
+++ b/contrib/hostapd/eap_defs.h
@@ -1,3 +1,17 @@
+/*
+ * WPA Supplicant/hostapd / Shared EAP definitions
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
#ifndef EAP_DEFS_H
#define EAP_DEFS_H
@@ -6,7 +20,7 @@
struct eap_hdr {
u8 code;
u8 identifier;
- u16 length; /* including code and identifier */
+ u16 length; /* including code and identifier; network byte order */
/* followed by length-4 octets of data */
} __attribute__ ((packed));
@@ -18,12 +32,12 @@ enum { EAP_CODE_REQUEST = 1, EAP_CODE_RESPONSE = 2, EAP_CODE_SUCCESS = 3,
typedef enum {
EAP_TYPE_NONE = 0,
- EAP_TYPE_IDENTITY = 1,
- EAP_TYPE_NOTIFICATION = 2,
- EAP_TYPE_NAK = 3 /* Response only */,
- EAP_TYPE_MD5 = 4,
- EAP_TYPE_OTP = 5 /* RFC 2284 */,
- EAP_TYPE_GTC = 6, /* RFC 2284 */
+ EAP_TYPE_IDENTITY = 1 /* RFC 3748 */,
+ EAP_TYPE_NOTIFICATION = 2 /* RFC 3748 */,
+ EAP_TYPE_NAK = 3 /* Response only, RFC 3748 */,
+ EAP_TYPE_MD5 = 4, /* RFC 3748 */
+ EAP_TYPE_OTP = 5 /* RFC 3748 */,
+ EAP_TYPE_GTC = 6, /* RFC 3748 */
EAP_TYPE_TLS = 13 /* RFC 2716 */,
EAP_TYPE_LEAP = 17 /* Cisco proprietary */,
EAP_TYPE_SIM = 18 /* draft-haverinen-pppext-eap-sim-12.txt */,
@@ -33,9 +47,10 @@ typedef enum {
EAP_TYPE_MSCHAPV2 = 26 /* draft-kamath-pppext-eap-mschapv2-00.txt */,
EAP_TYPE_TLV = 33 /* draft-josefsson-pppext-eap-tls-eap-07.txt */,
EAP_TYPE_FAST = 43 /* draft-cam-winget-eap-fast-00.txt */,
+ EAP_TYPE_PAX = 46, /* draft-clancy-eap-pax-04.txt */
EAP_TYPE_EXPANDED_NAK = 254 /* RFC 3748 */,
EAP_TYPE_PSK = 255 /* EXPERIMENTAL - type not yet allocated
- * draft-bersani-eap-psk-03 */
+ * draft-bersani-eap-psk-09 */
} EapType;
#endif /* EAP_DEFS_H */
diff --git a/contrib/hostapd/eap_i.h b/contrib/hostapd/eap_i.h
index 39b02579ef25..4e803f905d04 100644
--- a/contrib/hostapd/eap_i.h
+++ b/contrib/hostapd/eap_i.h
@@ -100,6 +100,8 @@ struct eap_sm {
void *eap_sim_db_priv;
Boolean backend_auth;
Boolean update_user;
+
+ int num_rounds;
};
const struct eap_method * eap_sm_get_eap_methods(int method);
diff --git a/contrib/hostapd/eap_identity.c b/contrib/hostapd/eap_identity.c
index 31aedc4e8255..54efc47961aa 100644
--- a/contrib/hostapd/eap_identity.c
+++ b/contrib/hostapd/eap_identity.c
@@ -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;
}
diff --git a/contrib/hostapd/eap_md5.c b/contrib/hostapd/eap_md5.c
index 5675c500d234..d776c8c82749 100644
--- a/contrib/hostapd/eap_md5.c
+++ b/contrib/hostapd/eap_md5.c
@@ -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");
diff --git a/contrib/hostapd/eap_pax.c b/contrib/hostapd/eap_pax.c
new file mode 100644
index 000000000000..2fbec870c9f1
--- /dev/null
+++ b/contrib/hostapd/eap_pax.c
@@ -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,
+};
diff --git a/contrib/hostapd/eap_pax_common.c b/contrib/hostapd/eap_pax_common.c
new file mode 100644
index 000000000000..d8f4016a6a09
--- /dev/null
+++ b/contrib/hostapd/eap_pax_common.c
@@ -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;
+}
diff --git a/contrib/hostapd/eap_pax_common.h b/contrib/hostapd/eap_pax_common.h
new file mode 100644
index 000000000000..b5ad6af1f2b9
--- /dev/null
+++ b/contrib/hostapd/eap_pax_common.h
@@ -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 */
diff --git a/contrib/hostapd/eap_peap.c b/contrib/hostapd/eap_peap.c
index aa91976e777a..9eb61a6b132f 100644
--- a/contrib/hostapd/eap_peap.c
+++ b/contrib/hostapd/eap_peap.c
@@ -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);
+ }
}
diff --git a/contrib/hostapd/eap_psk.c b/contrib/hostapd/eap_psk.c
new file mode 100644
index 000000000000..2f92d0577161
--- /dev/null
+++ b/contrib/hostapd/eap_psk.c
@@ -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,
+};
diff --git a/contrib/hostapd/eap_psk_common.c b/contrib/hostapd/eap_psk_common.c
new file mode 100644
index 000000000000..24de66cf0cb7
--- /dev/null
+++ b/contrib/hostapd/eap_psk_common.c
@@ -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++;
+ }
+}
diff --git a/contrib/hostapd/eap_psk_common.h b/contrib/hostapd/eap_psk_common.h
new file mode 100644
index 000000000000..5dd3a1042da3
--- /dev/null
+++ b/contrib/hostapd/eap_psk_common.h
@@ -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 */
diff --git a/contrib/hostapd/eap_sim.c b/contrib/hostapd/eap_sim.c
index aade18161d1d..fa60cf54d1c7 100644
--- a/contrib/hostapd/eap_sim.c
+++ b/contrib/hostapd/eap_sim.c
@@ -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"
diff --git a/contrib/hostapd/eap_sim_common.c b/contrib/hostapd/eap_sim_common.c
index 98f4fb7d3014..75947b7995a0 100644
--- a/contrib/hostapd/eap_sim_common.c
+++ b/contrib/hostapd/eap_sim_common.c
@@ -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 || req_len < EAP_SIM_MAC_LEN || mac < req ||
+ mac > req + req_len - EAP_SIM_MAC_LEN)
+ return -1;
- if (mac == NULL)
+ tmp = malloc(req_len);
+ if (tmp == NULL)
return -1;
- addr[0] = req;
+ 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);
+
+ 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",
- encr_data, encr_data_len);
+ decrypted, encr_data_len);
- if (eap_sim_parse_attr(encr_data, encr_data + encr_data_len, attr,
+ 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:
diff --git a/contrib/hostapd/eap_sim_common.h b/contrib/hostapd/eap_sim_common.h
index c89e04e410b9..6715c369c0b6 100644
--- a/contrib/hostapd/eap_sim_common.h
+++ b/contrib/hostapd/eap_sim_common.h
@@ -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;
diff --git a/contrib/hostapd/eap_sim_db.c b/contrib/hostapd/eap_sim_db.c
index 7f617ce860f1..a965fa461d26 100644
--- a/contrib/hostapd/eap_sim_db.c
+++ b/contrib/hostapd/eap_sim_db.c
@@ -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++;
diff --git a/contrib/hostapd/eap_tls.c b/contrib/hostapd/eap_tls.c
index 58ab2776a83c..bf76f5a50475 100644
--- a/contrib/hostapd/eap_tls.c
+++ b/contrib/hostapd/eap_tls.c
@@ -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;
+ }
}
diff --git a/contrib/hostapd/eap_tls_common.c b/contrib/hostapd/eap_tls_common.c
index ca10eca7e46e..d573064b616b 100644
--- a/contrib/hostapd/eap_tls_common.c
+++ b/contrib/hostapd/eap_tls_common.c
@@ -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;
}
diff --git a/contrib/hostapd/eap_ttls.c b/contrib/hostapd/eap_ttls.c
index 1e4be75c70b7..569b1c3cc2fb 100644
--- a/contrib/hostapd/eap_ttls.c
+++ b/contrib/hostapd/eap_ttls.c
@@ -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);
+ }
}
diff --git a/contrib/hostapd/eap_ttls.h b/contrib/hostapd/eap_ttls.h
index a187db4d34f7..f35f5a905997 100644
--- a/contrib/hostapd/eap_ttls.h
+++ b/contrib/hostapd/eap_ttls.h
@@ -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
diff --git a/contrib/hostapd/eapol_sm.c b/contrib/hostapd/eapol_sm.c
index fe710a6304a0..f2d5ec7c5298 100644
--- a/contrib/hostapd/eapol_sm.c
+++ b/contrib/hostapd/eapol_sm.c
@@ -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)
- state->reAuthWhen--;
+ if (state->quietWhile == 0) {
+ wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
+ " - quietWhile --> 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);
+ if (state->reAuthWhen > 0) {
+ state->reAuthWhen--;
+ if (state->reAuthWhen == 0) {
+ wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
+ " - reAuthWhen --> 0",
+ MAC2STR(state->addr));
+ }
+ }
- 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);
+
+ /*
+ * 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:
- 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;
+ 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 (eapol_sm_sta_entry_alive(hapd, addr) && sm->eap) {
- if (eap_sm_step(sm->eap))
+ 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)) {
+ 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 @@ restart:
}
+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,
};
diff --git a/contrib/hostapd/eapol_sm.h b/contrib/hostapd/eapol_sm.h
index c89dd021473f..0c34b4fcc23d 100644
--- a/contrib/hostapd/eapol_sm.h
+++ b/contrib/hostapd/eapol_sm.h
@@ -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;
diff --git a/contrib/hostapd/eloop.c b/contrib/hostapd/eloop.c
index 60715089beb2..39fccb8cfc59 100644
--- a/contrib/hostapd/eloop.c
+++ b/contrib/hostapd/eloop.c
@@ -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);
}
diff --git a/contrib/hostapd/eloop.h b/contrib/hostapd/eloop.h
index f5b884740421..c57e68266ff0 100644
--- a/contrib/hostapd/eloop.h
+++ b/contrib/hostapd/eloop.h
@@ -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 */
diff --git a/contrib/hostapd/hostap_common.h b/contrib/hostapd/hostap_common.h
index 003ad9ac6b58..78af287c3cf0 100644
--- a/contrib/hostapd/hostap_common.h
+++ b/contrib/hostapd/hostap_common.h
@@ -423,6 +423,7 @@ enum {
PRISM2_PARAM_PRIVACY_INVOKED = 37,
PRISM2_PARAM_TKIP_COUNTERMEASURES = 38,
PRISM2_PARAM_DROP_UNENCRYPTED = 39,
+ PRISM2_PARAM_SCAN_CHANNEL_MASK = 40,
};
enum { HOSTAP_ANTSEL_DO_NOT_TOUCH = 0, HOSTAP_ANTSEL_DIVERSITY = 1,
diff --git a/contrib/hostapd/hostapd.8 b/contrib/hostapd/hostapd.8
new file mode 100644
index 000000000000..8b02497803f8
--- /dev/null
+++ b/contrib/hostapd/hostapd.8
@@ -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).
diff --git a/contrib/hostapd/hostapd.c b/contrib/hostapd/hostapd.c
index 88196417a3be..086af6291b0f 100644
--- a/contrib/hostapd/hostapd.c
+++ b/contrib/hostapd/hostapd.c
@@ -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);
+}
+
+
+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 */
- va_end(ap);
+ 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 */
diff --git a/contrib/hostapd/hostapd.conf b/contrib/hostapd/hostapd.conf
index bb792dc26009..ecd766360410 100644
--- a/contrib/hostapd/hostapd.conf
+++ b/contrib/hostapd/hostapd.conf
@@ -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,16 +101,54 @@ 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
+# 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:
+# 5 = 40-bit WEP (also known as 64-bit WEP with 40 secret bits)
+# 13 = 104-bit WEP (also known as 128-bit WEP with 104 secret bits)
+#wep_key_len_broadcast=5
+#wep_key_len_unicast=5
+# Rekeying period in seconds. 0 = do not rekey (i.e., set keys only once)
+#wep_rekey_period=300
+
+# EAPOL-Key index workaround (set bit7) for WinXP Supplicant (needed only if
+# only broadcast keys are used)
+eapol_key_index_workaround=0
+
+# EAP reauthentication period in seconds (default: 3600 seconds; 0 = disable
+# 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.
-# Path for EAP authenticator user database
+# 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
@@ -124,31 +167,23 @@ eap_authenticator=0
# 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
-# Optional displayable message sent with EAP Request-Identity
-eap_message=hello
-
-# WEP rekeying (disabled if key lengths are not set or are set to 0)
-# Key lengths for default/broadcast and individual/unicast keys:
-# 5 = 40-bit WEP (also known as 64-bit WEP with 40 secret bits)
-# 13 = 104-bit WEP (also known as 128-bit WEP with 104 secret bits)
-#wep_key_len_broadcast=5
-#wep_key_len_unicast=5
-# Rekeying period in seconds. 0 = do not rekey (i.e., set keys only once)
-#wep_rekey_period=300
-
-# EAPOL-Key index workaround (set bit7) for WinXP Supplicant (needed only if
-# only broadcast keys are used)
-eapol_key_index_workaround=0
-
-# EAP reauthentication period in seconds (default: 3600 seconds; 0 = disable
-# reauthentication).
-#eap_reauth_period=3600
##### IEEE 802.11f - Inter-Access Point Protocol (IAPP) #######################
@@ -156,7 +191,7 @@ eapol_key_index_workaround=0
#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 ##########################################
diff --git a/contrib/hostapd/hostapd.eap_user b/contrib/hostapd/hostapd.eap_user
index 529334a0e157..fd7b420fb617 100644
--- a/contrib/hostapd/hostapd.eap_user
+++ b/contrib/hostapd/hostapd.eap_user
@@ -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
diff --git a/contrib/hostapd/hostapd.h b/contrib/hostapd/hostapd.h
index 9e6da65b6cdc..fdcb420ee27e 100644
--- a/contrib/hostapd/hostapd.h
+++ b/contrib/hostapd/hostapd.h
@@ -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 */
diff --git a/contrib/hostapd/hostapd_cli.1 b/contrib/hostapd/hostapd_cli.1
new file mode 100644
index 000000000000..062fc785897c
--- /dev/null
+++ b/contrib/hostapd/hostapd_cli.1
@@ -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).
diff --git a/contrib/hostapd/hostapd_cli.c b/contrib/hostapd/hostapd_cli.c
index 5e305dcee988..d93c41d57f8e 100644
--- a/contrib/hostapd/hostapd_cli.c
+++ b/contrib/hostapd/hostapd_cli.c
@@ -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";
-
-static struct hostapd_ctrl *ctrl_conn;
+"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 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");
diff --git a/contrib/hostapd/iapp.c b/contrib/hostapd/iapp.c
index 792a4714c4ff..f4dd5573cf0c 100644
--- a/contrib/hostapd/iapp.c
+++ b/contrib/hostapd/iapp.c
@@ -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"
diff --git a/contrib/hostapd/ieee802_11.c b/contrib/hostapd/ieee802_11.c
index 16a3d0e7741c..d5ad58cbb536 100644
--- a/contrib/hostapd/ieee802_11.c
+++ b/contrib/hostapd/ieee802_11.c
@@ -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,
diff --git a/contrib/hostapd/ieee802_11_auth.c b/contrib/hostapd/ieee802_11_auth.c
index 8dbcee188dfd..296c64017afd 100644
--- a/contrib/hostapd/ieee802_11_auth.c
+++ b/contrib/hostapd/ieee802_11_auth.c
@@ -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;
diff --git a/contrib/hostapd/ieee802_1x.c b/contrib/hostapd/ieee802_1x.c
index 7f3fe0c56fe2..fa44d82211bd 100644
--- a/contrib/hostapd/ieee802_1x.c
+++ b/contrib/hostapd/ieee802_1x.c
@@ -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;
- }
- 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;
- }
+ 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++;
}
- memcpy(sm->radius_class, class, class_len);
- sm->radius_class_len = class_len;
+ 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));
+}
+
+
+/* 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);
}
diff --git a/contrib/hostapd/ieee802_1x.h b/contrib/hostapd/ieee802_1x.h
index c52d7bb64333..0ac06b24bd9d 100644
--- a/contrib/hostapd/ieee802_1x.h
+++ b/contrib/hostapd/ieee802_1x.h
@@ -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 */
diff --git a/contrib/hostapd/l2_packet.h b/contrib/hostapd/l2_packet.h
index 3e3914ca5502..eb966d39ed69 100644
--- a/contrib/hostapd/l2_packet.h
+++ b/contrib/hostapd/l2_packet.h
@@ -1,3 +1,23 @@
+/*
+ * WPA Supplicant - Layer2 packet interface definition
+ * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ *
+ * This file defines an interface for layer 2 (link layer) packet sending and
+ * receiving. l2_packet_linux.c is one implementation for such a layer 2
+ * implementation using Linux packet sockets and l2_packet_pcap.c another one
+ * using libpcap and libdnet. When porting %wpa_supplicant to other operating
+ * systems, a new l2_packet implementation may need to be added.
+ */
+
#ifndef L2_PACKET_H
#define L2_PACKET_H
@@ -12,6 +32,14 @@
#define ETH_P_RSN_PREAUTH 0x88c7
#endif
+/**
+ * struct l2_packet_data - Internal l2_packet data structure
+ *
+ * This structure is used by the l2_packet implementation to store its private
+ * data. Other files use a pointer to this data when calling the l2_packet
+ * functions, but the contents of this structure should not be used directly
+ * outside l2_packet implementation.
+ */
struct l2_packet_data;
struct l2_ethhdr {
@@ -20,15 +48,86 @@ struct l2_ethhdr {
u16 h_proto;
} __attribute__ ((packed));
+/**
+ * l2_packet_init - Initialize l2_packet interface
+ * @ifname: Interface name
+ * @own_addr: Optional own MAC address if available from driver interface or
+ * %NULL if not available
+ * @protocol: Ethernet protocol number in host byte order
+ * @rx_callback: Callback function that will be called for each received packet
+ * @rx_callback_ctx: Callback data (ctx) for calls to rx_callback()
+ * @l2_hdr: 1 = include layer 2 header, 0 = do not include header
+ * Returns: Pointer to internal data or %NULL on failure
+ *
+ * rx_callback function will be called with src_addr pointing to the source
+ * address (MAC address) of the the packet. If l2_hdr is set to 0, buf
+ * points to len bytes of the payload after the layer 2 header and similarly,
+ * TX buffers start with payload. This behavior can be changed by setting
+ * l2_hdr=1 to include the layer 2 header in the data buffer.
+ */
struct l2_packet_data * l2_packet_init(
const char *ifname, const u8 *own_addr, unsigned short protocol,
- void (*rx_callback)(void *ctx, unsigned char *src_addr,
- unsigned char *buf, size_t len),
- void *rx_callback_ctx);
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len),
+ void *rx_callback_ctx, int l2_hdr);
+
+/**
+ * l2_packet_deinit - Deinitialize l2_packet interface
+ * @l2: Pointer to internal l2_packet data from l2_packet_init()
+ */
void l2_packet_deinit(struct l2_packet_data *l2);
+/**
+ * l2_packet_get_own_addr - Get own layer 2 address
+ * @l2: Pointer to internal l2_packet data from l2_packet_init()
+ * @addr: Buffer for the own address (6 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr);
-int l2_packet_send(struct l2_packet_data *l2, u8 *buf, size_t len);
-void l2_packet_set_rx_l2_hdr(struct l2_packet_data *l2, int rx_l2_hdr);
+
+/**
+ * l2_packet_send - Send a packet
+ * @l2: Pointer to internal l2_packet data from l2_packet_init()
+ * @dst_addr: Destination address for the packet (only used if l2_hdr == 0)
+ * @proto: Protocol/ethertype for the packet in host byte order (only used if
+ * l2_hdr == 0)
+ * @buf: Packet contents to be sent; including layer 2 header if l2_hdr was
+ * set to 1 in l2_packet_init() call. Otherwise, only the payload of the packet
+ * is included.
+ * @len: Length of the buffer (including l2 header only if l2_hdr == 1)
+ * Returns: >=0 on success, <0 on failure
+ */
+int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
+ const u8 *buf, size_t len);
+
+/**
+ * l2_packet_get_ip_addr - Get the current IP address from the interface
+ * @l2: Pointer to internal l2_packet data from l2_packet_init()
+ * @buf: Buffer for the IP address in text format
+ * @len: Maximum buffer length
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function can be used to get the current IP address from the interface
+ * bound to the l2_packet. This is mainly for status information and the IP
+ * address will be stored as an ASCII string. This function is not essential
+ * for %wpa_supplicant operation, so full implementation is not required.
+ * l2_packet implementation will need to define the function, but it can return
+ * -1 if the IP address information is not available.
+ */
+int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len);
+
+
+/**
+ * l2_packet_notify_auth_start - Notify l2_packet about start of authentication
+ * @l2: Pointer to internal l2_packet data from l2_packet_init()
+ *
+ * This function is called when authentication is expected to start, e.g., when
+ * association has been completed, in order to prepare l2_packet implementation
+ * for EAPOL frames. This function is used mainly if the l2_packet code needs
+ * to do polling in which case it can increasing polling frequency. This can
+ * also be an empty function if the l2_packet implementation does not benefit
+ * from knowing about the starting authentication.
+ */
+void l2_packet_notify_auth_start(struct l2_packet_data *l2);
#endif /* L2_PACKET_H */
diff --git a/contrib/hostapd/logwatch/README b/contrib/hostapd/logwatch/README
new file mode 100644
index 000000000000..3cba51190963
--- /dev/null
+++ b/contrib/hostapd/logwatch/README
@@ -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/
diff --git a/contrib/hostapd/logwatch/hostapd b/contrib/hostapd/logwatch/hostapd
new file mode 100755
index 000000000000..97b24ef6e1b8
--- /dev/null
+++ b/contrib/hostapd/logwatch/hostapd
@@ -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);
diff --git a/contrib/hostapd/logwatch/hostapd.conf b/contrib/hostapd/logwatch/hostapd.conf
new file mode 100644
index 000000000000..5bebe6ad2c1b
--- /dev/null
+++ b/contrib/hostapd/logwatch/hostapd.conf
@@ -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
diff --git a/contrib/hostapd/madwifi.conf b/contrib/hostapd/madwifi.conf
index f72750e3d7b6..a9bf539d236b 100644
--- a/contrib/hostapd/madwifi.conf
+++ b/contrib/hostapd/madwifi.conf
@@ -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
diff --git a/contrib/hostapd/md5.c b/contrib/hostapd/md5.c
index 1564e8f64797..82388e086766 100644
--- a/contrib/hostapd/md5.c
+++ b/contrib/hostapd/md5.c
@@ -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 */
diff --git a/contrib/hostapd/md5.h b/contrib/hostapd/md5.h
index cc3eb950b507..a724804943fc 100644
--- a/contrib/hostapd/md5.h
+++ b/contrib/hostapd/md5.h
@@ -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,
diff --git a/contrib/hostapd/ms_funcs.c b/contrib/hostapd/ms_funcs.c
index 590b58949d74..c26cddfb0775 100644
--- a/contrib/hostapd/ms_funcs.c
+++ b/contrib/hostapd/ms_funcs.c
@@ -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 */
diff --git a/contrib/hostapd/ms_funcs.h b/contrib/hostapd/ms_funcs.h
index a08ab06d72be..38d1bd63fe61 100644
--- a/contrib/hostapd/ms_funcs.h
+++ b/contrib/hostapd/ms_funcs.h
@@ -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 */
diff --git a/contrib/hostapd/radius.c b/contrib/hostapd/radius.c
index 5fd323d65c85..ce79a62c141c 100644
--- a/contrib/hostapd/radius.c
+++ b/contrib/hostapd/radius.c
@@ -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;
+}
diff --git a/contrib/hostapd/radius.h b/contrib/hostapd/radius.h
index 318e0adecf24..b9f8977f421e 100644
--- a/contrib/hostapd/radius.h
+++ b/contrib/hostapd/radius.h
@@ -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 */
diff --git a/contrib/hostapd/radius_client.c b/contrib/hostapd/radius_client.c
index dc69ca927397..abc28bdfc70d 100644
--- a/contrib/hostapd/radius_client.c
+++ b/contrib/hostapd/radius_client.c
@@ -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;
-
- hostapd_logger(hapd, NULL, HOSTAPD_MODULE_RADIUS, HOSTAPD_LEVEL_INFO,
+#ifdef CONFIG_IPV6
+ struct sockaddr_in6 serv6;
+#endif /* CONFIG_IPV6 */
+ struct sockaddr *addr;
+ socklen_t addrlen;
+ char abuf[50];
+ int sel_sock;
+
+ 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,23 +819,49 @@ 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 (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 "
+ "server\n");
+ return -1;
+ }
- if (eloop_register_read_sock(radius->auth_serv_sock,
+#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;
}
@@ -790,29 +869,45 @@ static int radius_client_init_auth(struct radius_client_data *radius)
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]");
+ else
+ ok++;
+
+ radius_change_server(radius, conf->acct_server, NULL,
+ radius->acct_serv_sock, radius->acct_serv_sock6,
+ 0);
+
+ 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 "
+ "server\n");
return -1;
}
- radius_change_server(radius, hapd->conf->acct_server, NULL,
- radius->acct_serv_sock, 0);
-
- if (eloop_register_read_sock(radius->acct_serv_sock,
+#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);
}
}
diff --git a/contrib/hostapd/radius_client.h b/contrib/hostapd/radius_client.h
index cff201a665e7..d21ca83faead 100644
--- a/contrib/hostapd/radius_client.h
+++ b/contrib/hostapd/radius_client.h
@@ -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,
diff --git a/contrib/hostapd/radius_server.c b/contrib/hostapd/radius_server.c
index d62648f896b1..bda8bd0a4d83 100644
--- a/contrib/hostapd/radius_server.c
+++ b/contrib/hostapd/radius_server.c
@@ -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 "
diff --git a/contrib/hostapd/radius_server.h b/contrib/hostapd/radius_server.h
index a725f0a5aebc..5c4c39c37ed1 100644
--- a/contrib/hostapd/radius_server.h
+++ b/contrib/hostapd/radius_server.h
@@ -9,6 +9,7 @@ struct radius_server_conf {
void *hostapd_conf;
void *eap_sim_db_priv;
void *ssl_ctx;
+ int ipv6;
};
diff --git a/contrib/hostapd/rc4.c b/contrib/hostapd/rc4.c
index 97ec1b0ae357..4cf14d91d1af 100644
--- a/contrib/hostapd/rc4.c
+++ b/contrib/hostapd/rc4.c
@@ -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);
}
diff --git a/contrib/hostapd/rc4.h b/contrib/hostapd/rc4.h
index 0e77b7e470d0..3873240496df 100644
--- a/contrib/hostapd/rc4.h
+++ b/contrib/hostapd/rc4.h
@@ -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 */
diff --git a/contrib/hostapd/sha1.c b/contrib/hostapd/sha1.c
index 04943b5a775c..7e32e31ca1ba 100644
--- a/contrib/hostapd/sha1.c
+++ b/contrib/hostapd/sha1.c
@@ -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];
diff --git a/contrib/hostapd/sha1.h b/contrib/hostapd/sha1.h
index 186e3c1c25b1..3c6d915146d9 100644
--- a/contrib/hostapd/sha1.h
+++ b/contrib/hostapd/sha1.h
@@ -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 */
diff --git a/contrib/hostapd/sta_info.c b/contrib/hostapd/sta_info.c
index 9a4daa362a71..9eb0bca2e367 100644
--- a/contrib/hostapd/sta_info.c
+++ b/contrib/hostapd/sta_info.c
@@ -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,
diff --git a/contrib/hostapd/sta_info.h b/contrib/hostapd/sta_info.h
index 417df71730e7..e2d7b4ef4b6b 100644
--- a/contrib/hostapd/sta_info.h
+++ b/contrib/hostapd/sta_info.h
@@ -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 */
diff --git a/contrib/hostapd/tls.h b/contrib/hostapd/tls.h
index 99c9b332360a..a6a8110c7dab 100644
--- a/contrib/hostapd/tls.h
+++ b/contrib/hostapd/tls.h
@@ -1,3 +1,17 @@
+/*
+ * WPA Supplicant / SSL/TLS interface definition
+ * Copyright (c) 2004-2006, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
#ifndef TLS_H
#define TLS_H
@@ -10,28 +24,115 @@ struct tls_keys {
size_t client_random_len;
const u8 *server_random;
size_t server_random_len;
+
+ /*
+ * If TLS library does not provide access to master_key, but only to
+ * EAP key block, this pointer can be set to point to the result of
+ * PRF(master_secret, "client EAP encryption",
+ * client_random + server_random).
+ */
+ const u8 *eap_tls_prf;
+ size_t eap_tls_prf_len;
+};
+
+struct tls_config {
+ const char *opensc_engine_path;
+ const char *pkcs11_engine_path;
+ const char *pkcs11_module_path;
};
/**
- * tls_init - initialize TLS library
- *
- * Returns: Context data to be used as @tls_ctx in calls to other functions,
+ * 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)
+ *
+ * TLS connection parameters to be configured with tls_connection_set_params().
+ *
+ * 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.
+ */
+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_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.
+ * 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(void);
+void * tls_init(const struct tls_config *conf);
/**
- * tls_deinit - deinitialize TLS library
+ * 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()
- * @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
+ * @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_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
- int verify_peer, const char *subject_match);
+int tls_global_set_verify(void *tls_ctx, int check_crl);
/**
- * tls_connection_client_cert - set client certificate for TLS connection
+ * tls_connection_set_verify - Set certificate verification options
* @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
+ * @verify_peer: 1 = verify peer certificate
*
* Returns: 0 on success, -1 on failure
*/
-int tls_connection_client_cert(void *tls_ctx, struct tls_connection *conn,
- const char *client_cert);
+int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
+ int verify_peer);
/**
- * 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 */
diff --git a/contrib/hostapd/tls_none.c b/contrib/hostapd/tls_none.c
index 2b3cafc10415..07fd879ec8c8 100644
--- a/contrib/hostapd/tls_none.c
+++ b/contrib/hostapd/tls_none.c
@@ -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;
}
diff --git a/contrib/hostapd/tls_openssl.c b/contrib/hostapd/tls_openssl.c
index 4e6ea539209f..08d5a800daab 100644
--- a/contrib/hostapd/tls_openssl.c
+++ b/contrib/hostapd/tls_openssl.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / SSL/TLS interface functions for openssl
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * 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
@@ -15,21 +15,504 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+
+#ifndef CONFIG_SMARTCARD
+#ifndef OPENSSL_NO_ENGINE
+#define OPENSSL_NO_ENGINE
+#endif
+#endif
+
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/pkcs12.h>
+#include <openssl/x509v3.h>
+#ifndef OPENSSL_NO_ENGINE
+#include <openssl/engine.h>
+#endif /* OPENSSL_NO_ENGINE */
#include "common.h"
#include "tls.h"
+#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
+#define OPENSSL_d2i_TYPE const unsigned char **
+#else
+#define OPENSSL_d2i_TYPE unsigned char **
+#endif
+
+static int tls_openssl_ref_count = 0;
struct tls_connection {
SSL *ssl;
BIO *ssl_in, *ssl_out;
- char *subject_match;
+#ifndef OPENSSL_NO_ENGINE
+ ENGINE *engine; /* functional reference to the engine */
+ EVP_PKEY *private_key; /* the private key if using engine */
+#endif /* OPENSSL_NO_ENGINE */
+ char *subject_match, *altsubject_match;
+ int read_alerts, write_alerts, failed;
+
+ u8 *pre_shared_secret;
+ size_t pre_shared_secret_len;
};
+#ifdef CONFIG_NO_STDOUT_DEBUG
+
+static void _tls_show_errors(void)
+{
+ unsigned long err;
+
+ while ((err = ERR_get_error())) {
+ /* Just ignore the errors, since stdout is disabled */
+ }
+}
+#define tls_show_errors(l, f, t) _tls_show_errors()
+
+#else /* CONFIG_NO_STDOUT_DEBUG */
+
+static void tls_show_errors(int level, const char *func, const char *txt)
+{
+ unsigned long err;
+
+ wpa_printf(level, "OpenSSL: %s - %s %s",
+ func, txt, ERR_error_string(ERR_get_error(), NULL));
+
+ while ((err = ERR_get_error())) {
+ wpa_printf(MSG_INFO, "OpenSSL: pending error: %s",
+ ERR_error_string(err, NULL));
+ }
+}
+
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+
+#ifdef CONFIG_NATIVE_WINDOWS
+
+/* Windows CryptoAPI and access to certificate stores */
+#include <wincrypt.h>
+
+#ifdef __MINGW32_VERSION
+/*
+ * MinGW does not yet include all the needed definitions for CryptoAPI, so
+ * define here whatever extra is needed.
+ */
+#define CALG_SSL3_SHAMD5 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SSL3SHAMD5)
+#define CERT_SYSTEM_STORE_CURRENT_USER (1 << 16)
+#define CERT_STORE_READONLY_FLAG 0x00008000
+#define CERT_STORE_OPEN_EXISTING_FLAG 0x00004000
+#define CRYPT_ACQUIRE_COMPARE_KEY_FLAG 0x00000004
+
+static BOOL WINAPI
+(*CryptAcquireCertificatePrivateKey)(PCCERT_CONTEXT pCert, DWORD dwFlags,
+ void *pvReserved, HCRYPTPROV *phCryptProv,
+ DWORD *pdwKeySpec, BOOL *pfCallerFreeProv)
+= NULL; /* to be loaded from crypt32.dll */
+
+static PCCERT_CONTEXT WINAPI
+(*CertEnumCertificatesInStore)(HCERTSTORE hCertStore,
+ PCCERT_CONTEXT pPrevCertContext)
+= NULL; /* to be loaded from crypt32.dll */
+
+static int mingw_load_crypto_func(void)
+{
+ HINSTANCE dll;
+
+ /* MinGW does not yet have full CryptoAPI support, so load the needed
+ * function here. */
+
+ if (CryptAcquireCertificatePrivateKey)
+ return 0;
+
+ dll = LoadLibrary("crypt32");
+ if (dll == NULL) {
+ wpa_printf(MSG_DEBUG, "CryptoAPI: Could not load crypt32 "
+ "library");
+ return -1;
+ }
+
+ CryptAcquireCertificatePrivateKey = GetProcAddress(
+ dll, "CryptAcquireCertificatePrivateKey");
+ if (CryptAcquireCertificatePrivateKey == NULL) {
+ wpa_printf(MSG_DEBUG, "CryptoAPI: Could not get "
+ "CryptAcquireCertificatePrivateKey() address from "
+ "crypt32 library");
+ return -1;
+ }
+
+ CertEnumCertificatesInStore = (void *) GetProcAddress(
+ dll, "CertEnumCertificatesInStore");
+ if (CertEnumCertificatesInStore == NULL) {
+ wpa_printf(MSG_DEBUG, "CryptoAPI: Could not get "
+ "CertEnumCertificatesInStore() address from "
+ "crypt32 library");
+ return -1;
+ }
+
+ return 0;
+}
+
+#else /* __MINGW32_VERSION */
+
+static int mingw_load_crypto_func(void)
+{
+ return 0;
+}
+
+#endif /* __MINGW32_VERSION */
+
+
+struct cryptoapi_rsa_data {
+ const CERT_CONTEXT *cert;
+ HCRYPTPROV crypt_prov;
+ DWORD key_spec;
+ BOOL free_crypt_prov;
+};
+
+
+static void cryptoapi_error(const char *msg)
+{
+ wpa_printf(MSG_INFO, "CryptoAPI: %s; err=%u",
+ msg, (unsigned int) GetLastError());
+}
+
+
+static int cryptoapi_rsa_pub_enc(int flen, const unsigned char *from,
+ unsigned char *to, RSA *rsa, int padding)
+{
+ wpa_printf(MSG_DEBUG, "%s - not implemented", __func__);
+ return 0;
+}
+
+
+static int cryptoapi_rsa_pub_dec(int flen, const unsigned char *from,
+ unsigned char *to, RSA *rsa, int padding)
+{
+ wpa_printf(MSG_DEBUG, "%s - not implemented", __func__);
+ return 0;
+}
+
+
+static int cryptoapi_rsa_priv_enc(int flen, const unsigned char *from,
+ unsigned char *to, RSA *rsa, int padding)
+{
+ struct cryptoapi_rsa_data *priv =
+ (struct cryptoapi_rsa_data *) rsa->meth->app_data;
+ HCRYPTHASH hash;
+ DWORD hash_size, len, i;
+ unsigned char *buf = NULL;
+ int ret = 0;
+
+ if (priv == NULL) {
+ RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
+ ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+
+ if (padding != RSA_PKCS1_PADDING) {
+ RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
+ RSA_R_UNKNOWN_PADDING_TYPE);
+ return 0;
+ }
+
+ if (flen != 16 /* MD5 */ + 20 /* SHA-1 */) {
+ wpa_printf(MSG_INFO, "%s - only MD5-SHA1 hash supported",
+ __func__);
+ RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
+ RSA_R_INVALID_MESSAGE_LENGTH);
+ return 0;
+ }
+
+ if (!CryptCreateHash(priv->crypt_prov, CALG_SSL3_SHAMD5, 0, 0, &hash))
+ {
+ cryptoapi_error("CryptCreateHash failed");
+ return 0;
+ }
+
+ len = sizeof(hash_size);
+ if (!CryptGetHashParam(hash, HP_HASHSIZE, (BYTE *) &hash_size, &len,
+ 0)) {
+ cryptoapi_error("CryptGetHashParam failed");
+ goto err;
+ }
+
+ if (hash_size != flen) {
+ wpa_printf(MSG_INFO, "CryptoAPI: Invalid hash size (%u != %d)",
+ (unsigned) hash_size, flen);
+ RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
+ RSA_R_INVALID_MESSAGE_LENGTH);
+ goto err;
+ }
+ if (!CryptSetHashParam(hash, HP_HASHVAL, (BYTE * ) from, 0)) {
+ cryptoapi_error("CryptSetHashParam failed");
+ goto err;
+ }
+
+ len = RSA_size(rsa);
+ buf = malloc(len);
+ if (buf == NULL) {
+ RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (!CryptSignHash(hash, priv->key_spec, NULL, 0, buf, &len)) {
+ cryptoapi_error("CryptSignHash failed");
+ goto err;
+ }
+
+ for (i = 0; i < len; i++)
+ to[i] = buf[len - i - 1];
+ ret = len;
+
+err:
+ free(buf);
+ CryptDestroyHash(hash);
+
+ return ret;
+}
+
+
+static int cryptoapi_rsa_priv_dec(int flen, const unsigned char *from,
+ unsigned char *to, RSA *rsa, int padding)
+{
+ wpa_printf(MSG_DEBUG, "%s - not implemented", __func__);
+ return 0;
+}
+
+
+static void cryptoapi_free_data(struct cryptoapi_rsa_data *priv)
+{
+ if (priv == NULL)
+ return;
+ if (priv->crypt_prov && priv->free_crypt_prov)
+ CryptReleaseContext(priv->crypt_prov, 0);
+ if (priv->cert)
+ CertFreeCertificateContext(priv->cert);
+ free(priv);
+}
+
+
+static int cryptoapi_finish(RSA *rsa)
+{
+ cryptoapi_free_data((struct cryptoapi_rsa_data *) rsa->meth->app_data);
+ free((void *) rsa->meth);
+ rsa->meth = NULL;
+ return 1;
+}
+
+
+static const CERT_CONTEXT * cryptoapi_find_cert(const char *name, DWORD store)
+{
+ HCERTSTORE cs;
+ const CERT_CONTEXT *ret = NULL;
+
+ cs = CertOpenStore((LPCSTR) CERT_STORE_PROV_SYSTEM, 0, 0,
+ store | CERT_STORE_OPEN_EXISTING_FLAG |
+ CERT_STORE_READONLY_FLAG, L"MY");
+ if (cs == NULL) {
+ cryptoapi_error("Failed to open 'My system store'");
+ return NULL;
+ }
+
+ if (strncmp(name, "cert://", 7) == 0) {
+ unsigned short wbuf[255];
+ MultiByteToWideChar(CP_ACP, 0, name + 7, -1,
+ wbuf, sizeof(wbuf));
+ ret = CertFindCertificateInStore(cs, X509_ASN_ENCODING |
+ PKCS_7_ASN_ENCODING,
+ 0, CERT_FIND_SUBJECT_STR,
+ wbuf, NULL);
+ } else if (strncmp(name, "hash://", 7) == 0) {
+ CRYPT_HASH_BLOB blob;
+ int len;
+ const char *hash = name + 7;
+ unsigned char *buf;
+
+ len = strlen(hash) / 2;
+ buf = malloc(len);
+ if (buf && hexstr2bin(hash, buf, len) == 0) {
+ blob.cbData = len;
+ blob.pbData = buf;
+ ret = CertFindCertificateInStore(cs,
+ X509_ASN_ENCODING |
+ PKCS_7_ASN_ENCODING,
+ 0, CERT_FIND_HASH,
+ &blob, NULL);
+ }
+ free(buf);
+ }
+
+ CertCloseStore(cs, 0);
+
+ return ret;
+}
+
+
+static int tls_cryptoapi_cert(SSL *ssl, const char *name)
+{
+ X509 *cert = NULL;
+ RSA *rsa = NULL, *pub_rsa;
+ struct cryptoapi_rsa_data *priv;
+ RSA_METHOD *rsa_meth;
+
+ if (name == NULL ||
+ (strncmp(name, "cert://", 7) != 0 &&
+ strncmp(name, "hash://", 7) != 0))
+ return -1;
+
+ priv = malloc(sizeof(*priv));
+ rsa_meth = malloc(sizeof(*rsa_meth));
+ if (priv == NULL || rsa_meth == NULL) {
+ wpa_printf(MSG_WARNING, "CryptoAPI: Failed to allocate memory "
+ "for CryptoAPI RSA method");
+ free(priv);
+ free(rsa_meth);
+ return -1;
+ }
+ memset(priv, 0, sizeof(*priv));
+ memset(rsa_meth, 0, sizeof(*rsa_meth));
+
+ priv->cert = cryptoapi_find_cert(name, CERT_SYSTEM_STORE_CURRENT_USER);
+ if (priv->cert == NULL) {
+ priv->cert = cryptoapi_find_cert(
+ name, CERT_SYSTEM_STORE_LOCAL_MACHINE);
+ }
+ if (priv->cert == NULL) {
+ wpa_printf(MSG_INFO, "CryptoAPI: Could not find certificate "
+ "'%s'", name);
+ goto err;
+ }
+
+ cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &priv->cert->pbCertEncoded,
+ priv->cert->cbCertEncoded);
+ if (cert == NULL) {
+ wpa_printf(MSG_INFO, "CryptoAPI: Could not process X509 DER "
+ "encoding");
+ goto err;
+ }
+
+ if (mingw_load_crypto_func())
+ goto err;
+
+ if (!CryptAcquireCertificatePrivateKey(priv->cert,
+ CRYPT_ACQUIRE_COMPARE_KEY_FLAG,
+ NULL, &priv->crypt_prov,
+ &priv->key_spec,
+ &priv->free_crypt_prov)) {
+ cryptoapi_error("Failed to acquire a private key for the "
+ "certificate");
+ goto err;
+ }
+
+ rsa_meth->name = "Microsoft CryptoAPI RSA Method";
+ rsa_meth->rsa_pub_enc = cryptoapi_rsa_pub_enc;
+ rsa_meth->rsa_pub_dec = cryptoapi_rsa_pub_dec;
+ rsa_meth->rsa_priv_enc = cryptoapi_rsa_priv_enc;
+ rsa_meth->rsa_priv_dec = cryptoapi_rsa_priv_dec;
+ rsa_meth->finish = cryptoapi_finish;
+ rsa_meth->flags = RSA_METHOD_FLAG_NO_CHECK;
+ rsa_meth->app_data = (char *) priv;
+
+ rsa = RSA_new();
+ if (rsa == NULL) {
+ SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE,
+ ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (!SSL_use_certificate(ssl, cert))
+ goto err;
+ pub_rsa = cert->cert_info->key->pkey->pkey.rsa;
+ X509_free(cert);
+ cert = NULL;
+
+ rsa->n = BN_dup(pub_rsa->n);
+ rsa->e = BN_dup(pub_rsa->e);
+ if (!RSA_set_method(rsa, rsa_meth))
+ goto err;
+
+ if (!SSL_use_RSAPrivateKey(ssl, rsa))
+ goto err;
+ RSA_free(rsa);
+
+ return 0;
+
+err:
+ if (cert)
+ X509_free(cert);
+ if (rsa)
+ RSA_free(rsa);
+ else {
+ free(rsa_meth);
+ cryptoapi_free_data(priv);
+ }
+ return -1;
+}
+
+
+static int tls_cryptoapi_ca_cert(SSL_CTX *ssl_ctx, SSL *ssl, const char *name)
+{
+ HCERTSTORE cs;
+ PCCERT_CONTEXT ctx = NULL;
+ X509 *cert;
+ char buf[128];
+
+ if (mingw_load_crypto_func())
+ return -1;
+
+ if (name == NULL || strncmp(name, "cert_store://", 13) != 0)
+ return -1;
+
+ cs = CertOpenSystemStore(0, name + 13);
+ if (cs == NULL) {
+ wpa_printf(MSG_DEBUG, "%s: failed to open system cert store "
+ "'%s': error=%d", __func__, name + 13,
+ (int) GetLastError());
+ return -1;
+ }
+
+ while ((ctx = CertEnumCertificatesInStore(cs, ctx))) {
+ cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &ctx->pbCertEncoded,
+ ctx->cbCertEncoded);
+ if (cert == NULL) {
+ wpa_printf(MSG_INFO, "CryptoAPI: Could not process "
+ "X509 DER encoding for CA cert");
+ continue;
+ }
+
+ X509_NAME_oneline(X509_get_subject_name(cert), buf,
+ sizeof(buf));
+ wpa_printf(MSG_DEBUG, "OpenSSL: Loaded CA certificate for "
+ "system certificate store: subject='%s'", buf);
+
+ if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) {
+ tls_show_errors(MSG_WARNING, __func__,
+ "Failed to add ca_cert to OpenSSL "
+ "certificate store");
+ }
+
+ X509_free(cert);
+ }
+
+ if (!CertCloseStore(cs, 0)) {
+ wpa_printf(MSG_DEBUG, "%s: failed to close system cert store "
+ "'%s': error=%d", __func__, name + 13,
+ (int) GetLastError());
+ }
+
+ return 0;
+}
+
+
+#else /* CONFIG_NATIVE_WINDOWS */
+
+static int tls_cryptoapi_cert(SSL *ssl, const char *name)
+{
+ return -1;
+}
+
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+
static void ssl_info_cb(const SSL *ssl, int where, int ret)
{
const char *str;
@@ -50,10 +533,18 @@ static void ssl_info_cb(const SSL *ssl, int where, int ret)
} else if (where & SSL_CB_ALERT) {
wpa_printf(MSG_INFO, "SSL: SSL3 alert: %s:%s:%s",
where & SSL_CB_READ ?
- "read (authentication server reported an error)" :
+ "read (remote end reported an error)" :
"write (local SSL3 detected an error)",
SSL_alert_type_string_long(ret),
SSL_alert_desc_string_long(ret));
+ if ((ret >> 8) == SSL3_AL_FATAL) {
+ struct tls_connection *conn =
+ SSL_get_app_data((SSL *) ssl);
+ if (where & SSL_CB_READ)
+ conn->read_alerts++;
+ else
+ conn->write_alerts++;
+ }
} else if (where & SSL_CB_EXIT && ret <= 0) {
wpa_printf(MSG_DEBUG, "SSL: %s:%s in %s",
str, ret == 0 ? "failed" : "error",
@@ -62,18 +553,160 @@ static void ssl_info_cb(const SSL *ssl, int where, int ret)
}
-void * tls_init(void)
+#ifndef OPENSSL_NO_ENGINE
+/**
+ * tls_engine_load_dynamic_generic - load any openssl engine
+ * @pre: an array of commands and values that load an engine initialized
+ * in the engine specific function
+ * @post: an array of commands and values that initialize an already loaded
+ * engine (or %NULL if not required)
+ * @id: the engine id of the engine to load (only required if post is not %NULL
+ *
+ * This function is a generic function that loads any openssl engine.
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+static int tls_engine_load_dynamic_generic(const char *pre[],
+ const char *post[], const char *id)
+{
+ ENGINE *engine;
+ const char *dynamic_id = "dynamic";
+
+ engine = ENGINE_by_id(id);
+ if (engine) {
+ ENGINE_free(engine);
+ wpa_printf(MSG_DEBUG, "ENGINE: engine '%s' is already "
+ "available", id);
+ return 0;
+ }
+ ERR_clear_error();
+
+ engine = ENGINE_by_id(dynamic_id);
+ if (engine == NULL) {
+ wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]",
+ dynamic_id,
+ ERR_error_string(ERR_get_error(), NULL));
+ return -1;
+ }
+
+ /* Perform the pre commands. This will load the engine. */
+ while (pre && pre[0]) {
+ wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", pre[0], pre[1]);
+ if (ENGINE_ctrl_cmd_string(engine, pre[0], pre[1], 0) == 0) {
+ wpa_printf(MSG_INFO, "ENGINE: ctrl cmd_string failed: "
+ "%s %s [%s]", pre[0], pre[1],
+ ERR_error_string(ERR_get_error(), NULL));
+ ENGINE_free(engine);
+ return -1;
+ }
+ pre += 2;
+ }
+
+ /*
+ * Free the reference to the "dynamic" engine. The loaded engine can
+ * now be looked up using ENGINE_by_id().
+ */
+ ENGINE_free(engine);
+
+ engine = ENGINE_by_id(id);
+ if (engine == NULL) {
+ wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]",
+ id, ERR_error_string(ERR_get_error(), NULL));
+ return -1;
+ }
+
+ while (post && post[0]) {
+ wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", post[0], post[1]);
+ if (ENGINE_ctrl_cmd_string(engine, post[0], post[1], 0) == 0) {
+ wpa_printf(MSG_DEBUG, "ENGINE: ctrl cmd_string failed:"
+ " %s %s [%s]", post[0], post[1],
+ ERR_error_string(ERR_get_error(), NULL));
+ ENGINE_remove(engine);
+ ENGINE_free(engine);
+ return -1;
+ }
+ post += 2;
+ }
+ ENGINE_free(engine);
+
+ return 0;
+}
+
+
+/**
+ * tls_engine_load_dynamic_pkcs11 - load the pkcs11 engine provided by opensc
+ * @pkcs11_so_path: pksc11_so_path from the configuration
+ * @pcks11_module_path: pkcs11_module_path from the configuration
+ */
+static int tls_engine_load_dynamic_pkcs11(const char *pkcs11_so_path,
+ const char *pkcs11_module_path)
+{
+ char *engine_id = "pkcs11";
+ const char *pre_cmd[] = {
+ "SO_PATH", pkcs11_so_path,
+ "ID", engine_id,
+ "LIST_ADD", "1",
+ /* "NO_VCHECK", "1", */
+ "LOAD", NULL,
+ NULL, NULL
+ };
+ const char *post_cmd[] = {
+ "MODULE_PATH", pkcs11_module_path,
+ NULL, NULL
+ };
+
+ if (!pkcs11_so_path || !pkcs11_module_path)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "ENGINE: Loading pkcs11 Engine from %s",
+ pkcs11_so_path);
+
+ return tls_engine_load_dynamic_generic(pre_cmd, post_cmd, engine_id);
+}
+
+
+/**
+ * tls_engine_load_dynamic_opensc - load the opensc engine provided by opensc
+ * @opensc_so_path: opensc_so_path from the configuration
+ */
+static int tls_engine_load_dynamic_opensc(const char *opensc_so_path)
+{
+ char *engine_id = "opensc";
+ const char *pre_cmd[] = {
+ "SO_PATH", opensc_so_path,
+ "ID", engine_id,
+ "LIST_ADD", "1",
+ "LOAD", NULL,
+ NULL, NULL
+ };
+
+ if (!opensc_so_path)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "ENGINE: Loading OpenSC Engine from %s",
+ opensc_so_path);
+
+ return tls_engine_load_dynamic_generic(pre_cmd, NULL, engine_id);
+}
+#endif /* OPENSSL_NO_ENGINE */
+
+
+void * tls_init(const struct tls_config *conf)
{
SSL_CTX *ssl;
- SSL_load_error_strings();
- SSL_library_init();
- /* TODO: if /dev/urandom is available, PRNG is seeded automatically.
- * If this is not the case, random data should be added here. */
+ if (tls_openssl_ref_count == 0) {
+ SSL_load_error_strings();
+ SSL_library_init();
+ /* TODO: if /dev/urandom is available, PRNG is seeded
+ * automatically. If this is not the case, random data should
+ * be added here. */
#ifdef PKCS12_FUNCS
- PKCS12_PBE_add();
+ PKCS12_PBE_add();
#endif /* PKCS12_FUNCS */
+ }
+ tls_openssl_ref_count++;
ssl = SSL_CTX_new(TLSv1_method());
if (ssl == NULL)
@@ -81,6 +714,23 @@ void * tls_init(void)
SSL_CTX_set_info_callback(ssl, ssl_info_cb);
+#ifndef OPENSSL_NO_ENGINE
+ if (conf &&
+ (conf->opensc_engine_path || conf->pkcs11_engine_path ||
+ conf->pkcs11_module_path)) {
+ wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine");
+ ERR_load_ENGINE_strings();
+ ENGINE_load_dynamic();
+
+ if (tls_engine_load_dynamic_opensc(conf->opensc_engine_path) ||
+ tls_engine_load_dynamic_pkcs11(conf->pkcs11_engine_path,
+ conf->pkcs11_module_path)) {
+ tls_deinit(ssl);
+ return NULL;
+ }
+ }
+#endif /* OPENSSL_NO_ENGINE */
+
return ssl;
}
@@ -89,8 +739,98 @@ void tls_deinit(void *ssl_ctx)
{
SSL_CTX *ssl = ssl_ctx;
SSL_CTX_free(ssl);
- ERR_free_strings();
- EVP_cleanup();
+
+ tls_openssl_ref_count--;
+ if (tls_openssl_ref_count == 0) {
+#ifndef OPENSSL_NO_ENGINE
+ ENGINE_cleanup();
+#endif /* OPENSSL_NO_ENGINE */
+ ERR_free_strings();
+ EVP_cleanup();
+ }
+}
+
+
+static int tls_engine_init(struct tls_connection *conn, const char *engine_id,
+ const char *pin, const char *key_id)
+{
+#ifndef OPENSSL_NO_ENGINE
+ int ret = -1;
+ if (engine_id == NULL) {
+ wpa_printf(MSG_ERROR, "ENGINE: Engine ID not set");
+ return -1;
+ }
+ if (pin == NULL) {
+ wpa_printf(MSG_ERROR, "ENGINE: Smartcard PIN not set");
+ return -1;
+ }
+ if (key_id == NULL) {
+ wpa_printf(MSG_ERROR, "ENGINE: Key Id not set");
+ return -1;
+ }
+
+ ERR_clear_error();
+ conn->engine = ENGINE_by_id(engine_id);
+ if (!conn->engine) {
+ wpa_printf(MSG_ERROR, "ENGINE: engine %s not available [%s]",
+ engine_id, ERR_error_string(ERR_get_error(), NULL));
+ goto err;
+ }
+ if (ENGINE_init(conn->engine) != 1) {
+ wpa_printf(MSG_ERROR, "ENGINE: engine init failed "
+ "(engine: %s) [%s]", engine_id,
+ ERR_error_string(ERR_get_error(), NULL));
+ goto err;
+ }
+ wpa_printf(MSG_DEBUG, "ENGINE: engine initialized");
+
+ if (ENGINE_ctrl_cmd_string(conn->engine, "PIN", pin, 0) == 0) {
+ wpa_printf(MSG_ERROR, "ENGINE: cannot set pin [%s]",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto err;
+ }
+ conn->private_key = ENGINE_load_private_key(conn->engine,
+ key_id, NULL, NULL);
+ if (!conn->private_key) {
+ wpa_printf(MSG_ERROR, "ENGINE: cannot load private key with id"
+ " '%s' [%s]", key_id,
+ ERR_error_string(ERR_get_error(), NULL));
+ ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
+ goto err;
+ }
+ return 0;
+
+err:
+ if (conn->engine) {
+ ENGINE_free(conn->engine);
+ conn->engine = NULL;
+ }
+
+ if (conn->private_key) {
+ EVP_PKEY_free(conn->private_key);
+ conn->private_key = NULL;
+ }
+
+ return ret;
+#else /* OPENSSL_NO_ENGINE */
+ return 0;
+#endif /* OPENSSL_NO_ENGINE */
+}
+
+
+static void tls_engine_deinit(struct tls_connection *conn)
+{
+#ifndef OPENSSL_NO_ENGINE
+ wpa_printf(MSG_DEBUG, "ENGINE: engine deinit");
+ if (conn->private_key) {
+ EVP_PKEY_free(conn->private_key);
+ conn->private_key = NULL;
+ }
+ if (conn->engine) {
+ ENGINE_finish(conn->engine);
+ conn->engine = NULL;
+ }
+#endif /* OPENSSL_NO_ENGINE */
}
@@ -119,22 +859,21 @@ struct tls_connection * tls_connection_init(void *ssl_ctx)
memset(conn, 0, sizeof(*conn));
conn->ssl = SSL_new(ssl);
if (conn->ssl == NULL) {
- wpa_printf(MSG_INFO, "TLS: Failed to initialize new SSL "
- "connection: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ tls_show_errors(MSG_INFO, __func__,
+ "Failed to initialize new SSL connection");
free(conn);
return NULL;
}
+ SSL_set_app_data(conn->ssl, conn);
SSL_set_options(conn->ssl,
SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
SSL_OP_SINGLE_DH_USE);
conn->ssl_in = BIO_new(BIO_s_mem());
if (!conn->ssl_in) {
- wpa_printf(MSG_INFO, "SSL: Failed to create a new BIO for "
- "ssl_in: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ tls_show_errors(MSG_INFO, __func__,
+ "Failed to create a new BIO for ssl_in");
SSL_free(conn->ssl);
free(conn);
return NULL;
@@ -142,9 +881,8 @@ struct tls_connection * tls_connection_init(void *ssl_ctx)
conn->ssl_out = BIO_new(BIO_s_mem());
if (!conn->ssl_out) {
- wpa_printf(MSG_INFO, "SSL: Failed to create a new BIO for "
- "ssl_out: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ tls_show_errors(MSG_INFO, __func__,
+ "Failed to create a new BIO for ssl_out");
SSL_free(conn->ssl);
BIO_free(conn->ssl_in);
free(conn);
@@ -161,8 +899,11 @@ void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
{
if (conn == NULL)
return;
+ free(conn->pre_shared_secret);
SSL_free(conn->ssl);
+ tls_engine_deinit(conn);
free(conn->subject_match);
+ free(conn->altsubject_match);
free(conn);
}
@@ -187,6 +928,55 @@ int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
}
+static int tls_match_altsubject(X509 *cert, const char *match)
+{
+ GENERAL_NAME *gen;
+ char *field, *tmp;
+ void *ext;
+ int i, found = 0;
+ size_t len;
+
+ ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
+
+ for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
+ gen = sk_GENERAL_NAME_value(ext, i);
+ switch (gen->type) {
+ case GEN_EMAIL:
+ field = "EMAIL";
+ break;
+ case GEN_DNS:
+ field = "DNS";
+ break;
+ case GEN_URI:
+ field = "URI";
+ break;
+ default:
+ field = NULL;
+ wpa_printf(MSG_DEBUG, "TLS: altSubjectName: "
+ "unsupported type=%d", gen->type);
+ break;
+ }
+
+ if (!field)
+ continue;
+
+ wpa_printf(MSG_DEBUG, "TLS: altSubjectName: %s:%s",
+ field, gen->d.ia5->data);
+ len = strlen(field) + 1 + strlen((char *) gen->d.ia5->data) +
+ 1;
+ tmp = malloc(len);
+ if (tmp == NULL)
+ continue;
+ snprintf(tmp, len, "%s:%s", field, gen->d.ia5->data);
+ if (strstr(tmp, match))
+ found++;
+ free(tmp);
+ }
+
+ return found;
+}
+
+
static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
{
char buf[256];
@@ -194,17 +984,18 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
int err, depth;
SSL *ssl;
struct tls_connection *conn;
- char *match;
+ char *match, *altmatch;
err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
err = X509_STORE_CTX_get_error(x509_ctx);
depth = X509_STORE_CTX_get_error_depth(x509_ctx);
ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
SSL_get_ex_data_X509_STORE_CTX_idx());
- X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256);
+ X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
conn = SSL_get_app_data(ssl);
match = conn ? conn->subject_match : NULL;
+ altmatch = conn ? conn->altsubject_match : NULL;
if (!preverify_ok) {
wpa_printf(MSG_WARNING, "TLS: Certificate verification failed,"
@@ -219,6 +1010,11 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not "
"match with '%s'", buf, match);
preverify_ok = 0;
+ } else if (depth == 0 && altmatch &&
+ !tls_match_altsubject(err_cert, altmatch)) {
+ wpa_printf(MSG_WARNING, "TLS: altSubjectName match "
+ "'%s' not found", altmatch);
+ preverify_ok = 0;
}
}
@@ -226,34 +1022,102 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
}
-int tls_connection_ca_cert(void *ssl_ctx, struct tls_connection *conn,
- const char *ca_cert, const char *subject_match)
+#ifndef OPENSSL_NO_STDIO
+static int tls_load_ca_der(void *_ssl_ctx, const char *ca_cert)
{
- if (conn == NULL)
+ SSL_CTX *ssl_ctx = _ssl_ctx;
+ X509_LOOKUP *lookup;
+ int ret = 0;
+
+ lookup = X509_STORE_add_lookup(ssl_ctx->cert_store,
+ X509_LOOKUP_file());
+ if (lookup == NULL) {
+ tls_show_errors(MSG_WARNING, __func__,
+ "Failed add lookup for X509 store");
return -1;
+ }
- free(conn->subject_match);
- conn->subject_match = NULL;
- if (subject_match) {
- conn->subject_match = strdup(subject_match);
- if (conn->subject_match == NULL)
- return -1;
+ if (!X509_LOOKUP_load_file(lookup, ca_cert, X509_FILETYPE_ASN1)) {
+ unsigned long err = ERR_peek_error();
+ tls_show_errors(MSG_WARNING, __func__,
+ "Failed load CA in DER format");
+ if (ERR_GET_LIB(err) == ERR_LIB_X509 &&
+ ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring "
+ "cert already in hash table error",
+ __func__);
+ } else
+ ret = -1;
}
- if (ca_cert) {
- if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, NULL) != 1)
- {
- wpa_printf(MSG_WARNING, "TLS: Failed to load root "
- "certificates: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ return ret;
+}
+#endif /* OPENSSL_NO_STDIO */
+
+
+static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn,
+ const char *ca_cert, const u8 *ca_cert_blob,
+ size_t ca_cert_blob_len, const char *ca_path)
+{
+ SSL_CTX *ssl_ctx = _ssl_ctx;
+
+ if (ca_cert_blob) {
+ X509 *cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &ca_cert_blob,
+ ca_cert_blob_len);
+ if (cert == NULL) {
+ tls_show_errors(MSG_WARNING, __func__,
+ "Failed to parse ca_cert_blob");
+ return -1;
+ }
+
+ if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) {
+ tls_show_errors(MSG_WARNING, __func__,
+ "Failed to add ca_cert_blob to "
+ "certificate store");
+ X509_free(cert);
return -1;
+ }
+ X509_free(cert);
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s - added ca_cert_blob "
+ "to certificate store", __func__);
+ SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
+ return 0;
+ }
+
+#ifdef CONFIG_NATIVE_WINDOWS
+ if (ca_cert && tls_cryptoapi_ca_cert(ssl_ctx, conn->ssl, ca_cert) ==
+ 0) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: Added CA certificates from "
+ "system certificate store");
+ SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
+ return 0;
+ }
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+ if (ca_cert || ca_path) {
+#ifndef OPENSSL_NO_STDIO
+ if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, ca_path) !=
+ 1) {
+ tls_show_errors(MSG_WARNING, __func__,
+ "Failed to load root certificates");
+ if (ca_cert &&
+ tls_load_ca_der(ssl_ctx, ca_cert) == 0) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s - loaded "
+ "DER format CA certificate",
+ __func__);
+ } else
+ return -1;
} else {
wpa_printf(MSG_DEBUG, "TLS: Trusted root "
"certificate(s) loaded");
tls_get_errors(ssl_ctx);
}
- SSL_set_app_data(conn->ssl, conn);
SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
+#else /* OPENSSL_NO_STDIO */
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO",
+ __func__);
+ return -1;
+#endif /* OPENSSL_NO_STDIO */
} else {
/* No ca_cert configured - do not try to verify server
* certificate */
@@ -270,26 +1134,51 @@ int tls_global_ca_cert(void *_ssl_ctx, const char *ca_cert)
if (ca_cert) {
if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, NULL) != 1)
{
- wpa_printf(MSG_WARNING, "TLS: Failed to load root "
- "certificates: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ tls_show_errors(MSG_WARNING, __func__,
+ "Failed to load root certificates");
return -1;
- } else {
- wpa_printf(MSG_DEBUG, "TLS: Trusted root "
- "certificate(s) loaded");
}
+
+ wpa_printf(MSG_DEBUG, "TLS: Trusted root "
+ "certificate(s) loaded");
+
+#ifndef OPENSSL_NO_STDIO
+ /* Add the same CAs to the client certificate requests */
+ SSL_CTX_set_client_CA_list(ssl_ctx,
+ SSL_load_client_CA_file(ca_cert));
+#endif /* OPENSSL_NO_STDIO */
}
return 0;
}
-int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
- int verify_peer, const char *subject_match)
+int tls_global_set_verify(void *ssl_ctx, int check_crl)
{
- if (conn == NULL)
- return -1;
+ int flags;
+
+ if (check_crl) {
+ X509_STORE *cs = SSL_CTX_get_cert_store(ssl_ctx);
+ if (cs == NULL) {
+ tls_show_errors(MSG_INFO, __func__, "Failed to get "
+ "certificate store when enabling "
+ "check_crl");
+ return -1;
+ }
+ flags = X509_V_FLAG_CRL_CHECK;
+ if (check_crl == 2)
+ flags |= X509_V_FLAG_CRL_CHECK_ALL;
+ X509_STORE_set_flags(cs, flags);
+ }
+ return 0;
+}
+
+static int tls_connection_set_subject_match(void *ssl_ctx,
+ struct tls_connection *conn,
+ const char *subject_match,
+ const char *altsubject_match)
+{
free(conn->subject_match);
conn->subject_match = NULL;
if (subject_match) {
@@ -298,8 +1187,25 @@ int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
return -1;
}
+ free(conn->altsubject_match);
+ conn->altsubject_match = NULL;
+ if (altsubject_match) {
+ conn->altsubject_match = strdup(altsubject_match);
+ if (conn->altsubject_match == NULL)
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
+ int verify_peer)
+{
+ if (conn == NULL)
+ return -1;
+
if (verify_peer) {
- SSL_set_app_data(conn->ssl, conn);
SSL_set_verify(conn->ssl, SSL_VERIFY_PEER |
SSL_VERIFY_FAIL_IF_NO_PEER_CERT |
SSL_VERIFY_CLIENT_ONCE, tls_verify_cb);
@@ -313,29 +1219,60 @@ int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
}
-int tls_connection_client_cert(void *ssl_ctx, struct tls_connection *conn,
- const char *client_cert)
+static int tls_connection_client_cert(void *ssl_ctx,
+ struct tls_connection *conn,
+ const char *client_cert,
+ const u8 *client_cert_blob,
+ size_t client_cert_blob_len)
{
- if (client_cert == NULL)
+ if (client_cert == NULL && client_cert_blob == NULL)
return 0;
- if (conn == NULL)
+
+ if (client_cert_blob &&
+ SSL_use_certificate_ASN1(conn->ssl, (u8 *) client_cert_blob,
+ client_cert_blob_len) == 1) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_ASN1 --> "
+ "OK");
+ return 0;
+ } else if (client_cert_blob) {
+ tls_show_errors(MSG_DEBUG, __func__,
+ "SSL_use_certificate_ASN1 failed");
+ }
+
+ if (client_cert == NULL)
return -1;
+#ifndef OPENSSL_NO_STDIO
if (SSL_use_certificate_file(conn->ssl, client_cert,
- SSL_FILETYPE_ASN1) != 1 &&
- SSL_use_certificate_file(conn->ssl, client_cert,
- SSL_FILETYPE_PEM) != 1) {
- wpa_printf(MSG_INFO, "TLS: Failed to load client "
- "certificate: %s",
- ERR_error_string(ERR_get_error(), NULL));
- return -1;
+ SSL_FILETYPE_ASN1) == 1) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (DER)"
+ " --> OK");
+ return 0;
+ } else {
+ tls_show_errors(MSG_DEBUG, __func__,
+ "SSL_use_certificate_file (DER) failed");
}
- return 0;
+
+ if (SSL_use_certificate_file(conn->ssl, client_cert,
+ SSL_FILETYPE_PEM) == 1) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (PEM)"
+ " --> OK");
+ return 0;
+ } else {
+ tls_show_errors(MSG_DEBUG, __func__,
+ "SSL_use_certificate_file (PEM) failed");
+ }
+#else /* OPENSSL_NO_STDIO */
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__);
+#endif /* OPENSSL_NO_STDIO */
+
+ return -1;
}
int tls_global_client_cert(void *_ssl_ctx, const char *client_cert)
{
+#ifndef OPENSSL_NO_STDIO
SSL_CTX *ssl_ctx = _ssl_ctx;
if (client_cert == NULL)
return 0;
@@ -344,12 +1281,17 @@ int tls_global_client_cert(void *_ssl_ctx, const char *client_cert)
SSL_FILETYPE_ASN1) != 1 &&
SSL_CTX_use_certificate_file(ssl_ctx, client_cert,
SSL_FILETYPE_PEM) != 1) {
- wpa_printf(MSG_INFO, "TLS: Failed to load client "
- "certificate: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ tls_show_errors(MSG_INFO, __func__,
+ "Failed to load client certificate");
return -1;
}
return 0;
+#else /* OPENSSL_NO_STDIO */
+ if (client_cert == NULL)
+ return 0;
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__);
+ return -1;
+#endif /* OPENSSL_NO_STDIO */
}
@@ -364,42 +1306,31 @@ static int tls_passwd_cb(char *buf, int size, int rwflag, void *password)
}
-static int tls_read_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, const char *private_key,
- const char *passwd)
-{
#ifdef PKCS12_FUNCS
- FILE *f;
- PKCS12 *p12;
+static int tls_parse_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, PKCS12 *p12,
+ const char *passwd)
+{
EVP_PKEY *pkey;
X509 *cert;
+ STACK_OF(X509) *certs;
int res = 0;
-
- f = fopen(private_key, "r");
- if (f == NULL)
- return -1;
-
- p12 = d2i_PKCS12_fp(f, NULL);
- if (p12 == NULL) {
- wpa_printf(MSG_DEBUG, "TLS: Failed to read PKCS12 file '%s'",
- private_key);
- fclose(f);
- return -1;
- }
- fclose(f);
+ char buf[256];
pkey = NULL;
cert = NULL;
- if (!PKCS12_parse(p12, passwd, &pkey, &cert, NULL)) {
- wpa_printf(MSG_DEBUG, "TLS: Failed to parse PKCS12 file '%s': "
- "%s", private_key,
- ERR_error_string(ERR_get_error(), NULL));
+ certs = NULL;
+ if (!PKCS12_parse(p12, passwd, &pkey, &cert, &certs)) {
+ tls_show_errors(MSG_DEBUG, __func__,
+ "Failed to parse PKCS12 file");
return -1;
}
- wpa_printf(MSG_DEBUG, "TLS: Successfully parsed PKCS12 file '%s'",
- private_key);
+ wpa_printf(MSG_DEBUG, "TLS: Successfully parsed PKCS12 data");
if (cert) {
- wpa_printf(MSG_DEBUG, "TLS: Got certificate from PKCS12");
+ X509_NAME_oneline(X509_get_subject_name(cert), buf,
+ sizeof(buf));
+ wpa_printf(MSG_DEBUG, "TLS: Got certificate from PKCS12: "
+ "subject='%s'", buf);
if (ssl) {
if (SSL_use_certificate(ssl, cert) != 1)
res = -1;
@@ -422,9 +1353,56 @@ static int tls_read_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, const char *private_key,
EVP_PKEY_free(pkey);
}
+ if (certs) {
+ while ((cert = sk_X509_pop(certs)) != NULL) {
+ X509_NAME_oneline(X509_get_subject_name(cert), buf,
+ sizeof(buf));
+ wpa_printf(MSG_DEBUG, "TLS: additional certificate"
+ " from PKCS12: subject='%s'", buf);
+ /*
+ * There is no SSL equivalent for the chain cert - so
+ * always add it to the context...
+ */
+ if (SSL_CTX_add_extra_chain_cert(ssl_ctx, cert) != 1) {
+ res = -1;
+ break;
+ }
+ }
+ sk_X509_free(certs);
+ }
+
PKCS12_free(p12);
+ if (res < 0)
+ tls_get_errors(ssl_ctx);
+
return res;
+}
+#endif /* PKCS12_FUNCS */
+
+
+static int tls_read_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, const char *private_key,
+ const char *passwd)
+{
+#ifdef PKCS12_FUNCS
+ FILE *f;
+ PKCS12 *p12;
+
+ f = fopen(private_key, "r");
+ if (f == NULL)
+ return -1;
+
+ p12 = d2i_PKCS12_fp(f, NULL);
+ fclose(f);
+
+ if (p12 == NULL) {
+ tls_show_errors(MSG_INFO, __func__,
+ "Failed to use PKCS#12 file");
+ return -1;
+ }
+
+ return tls_parse_pkcs12(ssl_ctx, ssl, p12, passwd);
+
#else /* PKCS12_FUNCS */
wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot read "
"p12/pfx files");
@@ -433,17 +1411,65 @@ static int tls_read_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, const char *private_key,
}
-int tls_connection_private_key(void *_ssl_ctx, struct tls_connection *conn,
- const char *private_key,
- const char *private_key_passwd)
+static int tls_read_pkcs12_blob(SSL_CTX *ssl_ctx, SSL *ssl,
+ const u8 *blob, size_t len, const char *passwd)
+{
+#ifdef PKCS12_FUNCS
+ PKCS12 *p12;
+
+ p12 = d2i_PKCS12(NULL, (OPENSSL_d2i_TYPE) &blob, len);
+ if (p12 == NULL) {
+ tls_show_errors(MSG_INFO, __func__,
+ "Failed to use PKCS#12 blob");
+ return -1;
+ }
+
+ return tls_parse_pkcs12(ssl_ctx, ssl, p12, passwd);
+
+#else /* PKCS12_FUNCS */
+ wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot parse "
+ "p12/pfx blobs");
+ return -1;
+#endif /* PKCS12_FUNCS */
+}
+
+
+static int tls_connection_engine_private_key(void *_ssl_ctx,
+ struct tls_connection *conn)
+{
+#ifndef OPENSSL_NO_ENGINE
+ if (SSL_use_PrivateKey(conn->ssl, conn->private_key) != 1) {
+ tls_show_errors(MSG_ERROR, __func__,
+ "ENGINE: cannot use private key for TLS");
+ return -1;
+ }
+ if (!SSL_check_private_key(conn->ssl)) {
+ tls_show_errors(MSG_INFO, __func__,
+ "Private key failed verification");
+ return -1;
+ }
+ return 0;
+#else /* OPENSSL_NO_ENGINE */
+ wpa_printf(MSG_ERROR, "SSL: Configuration uses engine, but "
+ "engine support was not compiled in");
+ return -1;
+#endif /* OPENSSL_NO_ENGINE */
+}
+
+
+static int tls_connection_private_key(void *_ssl_ctx,
+ struct tls_connection *conn,
+ const char *private_key,
+ const char *private_key_passwd,
+ const u8 *private_key_blob,
+ size_t private_key_blob_len)
{
SSL_CTX *ssl_ctx = _ssl_ctx;
char *passwd;
+ int ok;
- if (private_key == NULL)
+ if (private_key == NULL && private_key_blob == NULL)
return 0;
- if (conn == NULL)
- return -1;
if (private_key_passwd) {
passwd = strdup(private_key_passwd);
@@ -454,28 +1480,123 @@ int tls_connection_private_key(void *_ssl_ctx, struct tls_connection *conn,
SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb);
SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd);
- if (SSL_use_PrivateKey_file(conn->ssl, private_key,
- SSL_FILETYPE_ASN1) != 1 &&
- SSL_use_PrivateKey_file(conn->ssl, private_key,
- SSL_FILETYPE_PEM) != 1 &&
- tls_read_pkcs12(ssl_ctx, conn->ssl, private_key, passwd)) {
- wpa_printf(MSG_INFO, "SSL: Failed to load private key: %s",
- ERR_error_string(ERR_get_error(), NULL));
+
+ ok = 0;
+ while (private_key_blob) {
+ if (SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA, conn->ssl,
+ (u8 *) private_key_blob,
+ private_key_blob_len) == 1) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_"
+ "ASN1(EVP_PKEY_RSA) --> OK");
+ ok = 1;
+ break;
+ } else {
+ tls_show_errors(MSG_DEBUG, __func__,
+ "SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA)"
+ " failed");
+ }
+
+ if (SSL_use_PrivateKey_ASN1(EVP_PKEY_DSA, conn->ssl,
+ (u8 *) private_key_blob,
+ private_key_blob_len) == 1) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_"
+ "ASN1(EVP_PKEY_DSA) --> OK");
+ ok = 1;
+ break;
+ } else {
+ tls_show_errors(MSG_DEBUG, __func__,
+ "SSL_use_PrivateKey_ASN1(EVP_PKEY_DSA)"
+ " failed");
+ }
+
+ if (SSL_use_RSAPrivateKey_ASN1(conn->ssl,
+ (u8 *) private_key_blob,
+ private_key_blob_len) == 1) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: "
+ "SSL_use_RSAPrivateKey_ASN1 --> OK");
+ ok = 1;
+ break;
+ } else {
+ tls_show_errors(MSG_DEBUG, __func__,
+ "SSL_use_RSAPrivateKey_ASN1 failed");
+ }
+
+ if (tls_read_pkcs12_blob(ssl_ctx, conn->ssl, private_key_blob,
+ private_key_blob_len, passwd) == 0) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: PKCS#12 as blob --> "
+ "OK");
+ ok = 1;
+ break;
+ }
+
+ break;
+ }
+
+ while (!ok && private_key) {
+#ifndef OPENSSL_NO_STDIO
+ if (SSL_use_PrivateKey_file(conn->ssl, private_key,
+ SSL_FILETYPE_ASN1) == 1) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: "
+ "SSL_use_PrivateKey_File (DER) --> OK");
+ ok = 1;
+ break;
+ } else {
+ tls_show_errors(MSG_DEBUG, __func__,
+ "SSL_use_PrivateKey_File (DER) "
+ "failed");
+ }
+
+ if (SSL_use_PrivateKey_file(conn->ssl, private_key,
+ SSL_FILETYPE_PEM) == 1) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: "
+ "SSL_use_PrivateKey_File (PEM) --> OK");
+ ok = 1;
+ break;
+ } else {
+ tls_show_errors(MSG_DEBUG, __func__,
+ "SSL_use_PrivateKey_File (PEM) "
+ "failed");
+ }
+#else /* OPENSSL_NO_STDIO */
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO",
+ __func__);
+#endif /* OPENSSL_NO_STDIO */
+
+ if (tls_read_pkcs12(ssl_ctx, conn->ssl, private_key, passwd)
+ == 0) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: Reading PKCS#12 file "
+ "--> OK");
+ ok = 1;
+ break;
+ }
+
+ if (tls_cryptoapi_cert(conn->ssl, private_key) == 0) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: Using CryptoAPI to "
+ "access certificate store --> OK");
+ ok = 1;
+ break;
+ }
+
+ break;
+ }
+
+ if (!ok) {
+ wpa_printf(MSG_INFO, "OpenSSL: Failed to load private key");
free(passwd);
ERR_clear_error();
return -1;
}
ERR_clear_error();
- free(passwd);
SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL);
+ free(passwd);
if (!SSL_check_private_key(conn->ssl)) {
- wpa_printf(MSG_INFO, "SSL: Private key failed "
- "verification: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ tls_show_errors(MSG_INFO, __func__, "Private key failed "
+ "verification");
return -1;
}
+ wpa_printf(MSG_DEBUG, "SSL: Private key loaded successfully");
return 0;
}
@@ -498,13 +1619,16 @@ int tls_global_private_key(void *_ssl_ctx, const char *private_key,
SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb);
SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd);
- if (SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key,
+ if (
+#ifndef OPENSSL_NO_STDIO
+ SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key,
SSL_FILETYPE_ASN1) != 1 &&
SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key,
SSL_FILETYPE_PEM) != 1 &&
+#endif /* OPENSSL_NO_STDIO */
tls_read_pkcs12(ssl_ctx, NULL, private_key, passwd)) {
- wpa_printf(MSG_INFO, "SSL: Failed to load private key: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ tls_show_errors(MSG_INFO, __func__,
+ "Failed to load private key");
free(passwd);
ERR_clear_error();
return -1;
@@ -514,9 +1638,8 @@ int tls_global_private_key(void *_ssl_ctx, const char *private_key,
SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL);
if (!SSL_CTX_check_private_key(ssl_ctx)) {
- wpa_printf(MSG_INFO, "SSL: Private key failed "
- "verification: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ tls_show_errors(MSG_INFO, __func__,
+ "Private key failed verification");
return -1;
}
@@ -524,7 +1647,7 @@ int tls_global_private_key(void *_ssl_ctx, const char *private_key,
}
-int tls_connection_dh(void *ssl_ctx, struct tls_connection *conn,
+static int tls_connection_dh(void *ssl_ctx, struct tls_connection *conn,
const char *dh_file)
{
#ifdef OPENSSL_NO_DH
@@ -537,6 +1660,7 @@ int tls_connection_dh(void *ssl_ctx, struct tls_connection *conn,
DH *dh;
BIO *bio;
+ /* TODO: add support for dh_blob */
if (dh_file == NULL)
return 0;
if (conn == NULL)
@@ -609,6 +1733,7 @@ int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL)
return -1;
+ memset(keys, 0, sizeof(*keys));
keys->master_key = ssl->session->master_key;
keys->master_key_len = ssl->session->master_key_length;
keys->client_random = ssl->s3->client_random;
@@ -627,13 +1752,18 @@ u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
int res;
u8 *out_data;
+ /*
+ * Give TLS handshake data from the server (if available) to OpenSSL
+ * for processing.
+ */
if (in_data &&
BIO_write(conn->ssl_in, in_data, in_len) < 0) {
- wpa_printf(MSG_INFO, "TLS: Handshake failed - BIO_write: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ tls_show_errors(MSG_INFO, __func__,
+ "Handshake failed - BIO_write");
return NULL;
}
+ /* Initiate TLS handshake or continue the existing handshake */
res = SSL_connect(conn->ssl);
if (res != 1) {
int err = SSL_get_error(conn->ssl, res);
@@ -644,27 +1774,33 @@ u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want to "
"write");
else {
- wpa_printf(MSG_INFO, "SSL: SSL_connect: %s",
- ERR_error_string(ERR_get_error(), NULL));
- return NULL;
+ tls_show_errors(MSG_INFO, __func__, "SSL_connect");
+ conn->failed++;
}
}
+ /* Get the TLS handshake data to be sent to the server */
res = BIO_ctrl_pending(conn->ssl_out);
wpa_printf(MSG_DEBUG, "SSL: %d bytes pending from ssl_out", res);
out_data = malloc(res == 0 ? 1 : res);
if (out_data == NULL) {
wpa_printf(MSG_DEBUG, "SSL: Failed to allocate memory for "
"handshake output (%d bytes)", res);
- BIO_reset(conn->ssl_out);
+ if (BIO_reset(conn->ssl_out) < 0) {
+ tls_show_errors(MSG_INFO, __func__,
+ "BIO_reset failed");
+ }
*out_len = 0;
return NULL;
}
res = res == 0 ? 0 : BIO_read(conn->ssl_out, out_data, res);
if (res < 0) {
- wpa_printf(MSG_INFO, "TLS: Handshake failed - BIO_read: %s",
- ERR_error_string(ERR_get_error(), NULL));
- BIO_reset(conn->ssl_out);
+ tls_show_errors(MSG_INFO, __func__,
+ "Handshake failed - BIO_read");
+ if (BIO_reset(conn->ssl_out) < 0) {
+ tls_show_errors(MSG_INFO, __func__,
+ "BIO_reset failed");
+ }
*out_len = 0;
return NULL;
}
@@ -684,8 +1820,8 @@ u8 * tls_connection_server_handshake(void *ssl_ctx,
if (in_data &&
BIO_write(conn->ssl_in, in_data, in_len) < 0) {
- wpa_printf(MSG_INFO, "TLS: Handshake failed - BIO_write: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ tls_show_errors(MSG_INFO, __func__,
+ "Handshake failed - BIO_write");
return NULL;
}
@@ -701,15 +1837,21 @@ u8 * tls_connection_server_handshake(void *ssl_ctx,
if (out_data == NULL) {
wpa_printf(MSG_DEBUG, "SSL: Failed to allocate memory for "
"handshake output (%d bytes)", res);
- BIO_reset(conn->ssl_out);
+ if (BIO_reset(conn->ssl_out) < 0) {
+ tls_show_errors(MSG_INFO, __func__,
+ "BIO_reset failed");
+ }
*out_len = 0;
return NULL;
}
res = res == 0 ? 0 : BIO_read(conn->ssl_out, out_data, res);
if (res < 0) {
- wpa_printf(MSG_INFO, "TLS: Handshake failed - BIO_read: %s",
- ERR_error_string(ERR_get_error(), NULL));
- BIO_reset(conn->ssl_out);
+ tls_show_errors(MSG_INFO, __func__,
+ "Handshake failed - BIO_read");
+ if (BIO_reset(conn->ssl_out) < 0) {
+ tls_show_errors(MSG_INFO, __func__,
+ "BIO_reset failed");
+ }
*out_len = 0;
return NULL;
}
@@ -719,7 +1861,7 @@ u8 * tls_connection_server_handshake(void *ssl_ctx,
int tls_connection_encrypt(void *ssl_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)
{
int res;
@@ -727,19 +1869,24 @@ int tls_connection_encrypt(void *ssl_ctx, struct tls_connection *conn,
if (conn == NULL)
return -1;
- BIO_reset(conn->ssl_in);
- BIO_reset(conn->ssl_out);
+ /* Give plaintext data for OpenSSL to encrypt into the TLS tunnel. */
+ if ((res = BIO_reset(conn->ssl_in)) < 0 ||
+ (res = BIO_reset(conn->ssl_out)) < 0) {
+ tls_show_errors(MSG_INFO, __func__, "BIO_reset failed");
+ return res;
+ }
res = SSL_write(conn->ssl, in_data, in_len);
if (res < 0) {
- wpa_printf(MSG_INFO, "TLS: Encryption failed - SSL_write: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ tls_show_errors(MSG_INFO, __func__,
+ "Encryption failed - SSL_write");
return res;
}
+ /* Read encrypted data to be sent to the server */
res = BIO_read(conn->ssl_out, out_data, out_len);
if (res < 0) {
- wpa_printf(MSG_INFO, "TLS: Encryption failed - BIO_read: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ tls_show_errors(MSG_INFO, __func__,
+ "Encryption failed - BIO_read");
return res;
}
@@ -748,23 +1895,28 @@ int tls_connection_encrypt(void *ssl_ctx, struct tls_connection *conn,
int tls_connection_decrypt(void *ssl_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)
{
int res;
+ /* Give encrypted data from TLS tunnel for OpenSSL to decrypt. */
res = BIO_write(conn->ssl_in, in_data, in_len);
if (res < 0) {
- wpa_printf(MSG_INFO, "TLS: Decryption failed - BIO_write: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ tls_show_errors(MSG_INFO, __func__,
+ "Decryption failed - BIO_write");
+ return res;
+ }
+ if (BIO_reset(conn->ssl_out) < 0) {
+ tls_show_errors(MSG_INFO, __func__, "BIO_reset failed");
return res;
}
- BIO_reset(conn->ssl_out);
+ /* Read decrypted data for further processing */
res = SSL_read(conn->ssl, out_data, out_len);
if (res < 0) {
- wpa_printf(MSG_INFO, "TLS: Decryption failed - SSL_read: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ tls_show_errors(MSG_INFO, __func__,
+ "Decryption failed - SSL_read");
return res;
}
@@ -778,22 +1930,54 @@ int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
}
+#ifdef EAP_FAST
+/* Pre-shared secred requires a patch to openssl, so this function is
+ * commented out unless explicitly needed for EAP-FAST in order to be able to
+ * build this file with unmodified openssl. */
+
+static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
+ STACK_OF(SSL_CIPHER) *peer_ciphers,
+ SSL_CIPHER **cipher, void *arg)
+{
+ struct tls_connection *conn = arg;
+
+ if (conn == NULL || conn->pre_shared_secret == 0)
+ return 0;
+
+ memcpy(secret, conn->pre_shared_secret, conn->pre_shared_secret_len);
+ *secret_len = conn->pre_shared_secret_len;
+
+ return 1;
+}
+
+
int tls_connection_set_master_key(void *ssl_ctx, struct tls_connection *conn,
const u8 *key, size_t key_len)
{
- SSL *ssl;
-
- if (conn == NULL || key == NULL || key_len > SSL_MAX_MASTER_KEY_LENGTH)
- return -1;
- ssl = conn->ssl;
- if (ssl == NULL || ssl->session == NULL)
+ if (conn == NULL || key_len > SSL_MAX_MASTER_KEY_LENGTH)
return -1;
- memcpy(ssl->session->master_key, key, key_len);
- ssl->session->master_key_length = key_len;
+ free(conn->pre_shared_secret);
+ conn->pre_shared_secret = NULL;
+ conn->pre_shared_secret_len = 0;
+
+ if (key) {
+ conn->pre_shared_secret = malloc(key_len);
+ if (conn->pre_shared_secret) {
+ memcpy(conn->pre_shared_secret, key, key_len);
+ conn->pre_shared_secret_len = key_len;
+ }
+ if (SSL_set_session_secret_cb(conn->ssl, tls_sess_sec_cb,
+ conn) != 1)
+ return -1;
+ } else {
+ if (SSL_set_session_secret_cb(conn->ssl, NULL, NULL) != 1)
+ return -1;
+ }
return 0;
}
+#endif /* EAP_FAST */
int tls_connection_set_anon_dh(void *ssl_ctx, struct tls_connection *conn)
@@ -802,8 +1986,8 @@ int tls_connection_set_anon_dh(void *ssl_ctx, struct tls_connection *conn)
return -1;
if (SSL_set_cipher_list(conn->ssl, "ADH-AES128-SHA") != 1) {
- wpa_printf(MSG_INFO, "TLS: Anon DH configuration failed - %s",
- ERR_error_string(ERR_get_error(), NULL));
+ tls_show_errors(MSG_INFO, __func__,
+ "Anon DH configuration failed");
return -1;
}
@@ -844,36 +2028,116 @@ int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
int ext_type, const u8 *data,
size_t data_len)
{
- struct tls_ext_hdr {
- u16 extensions_len;
- u16 extension_type;
- u16 extension_len;
- } *hdr;
-
if (conn == NULL || conn->ssl == NULL)
return -1;
- OPENSSL_free(conn->ssl->hello_extension);
- if (data == NULL) {
- conn->ssl->hello_extension = NULL;
- conn->ssl->hello_extension_len = 0;
- return 0;
+
+ if (SSL_set_hello_extension(conn->ssl, ext_type, (void *) data,
+ data_len) != 1)
+ return -1;
+
+ return 0;
+}
+#endif /* EAP_FAST */
+
+
+int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
+{
+ if (conn == NULL)
+ return -1;
+ return conn->failed;
+}
+
+
+int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
+{
+ if (conn == NULL)
+ return -1;
+ return conn->read_alerts;
+}
+
+
+int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
+{
+ if (conn == NULL)
+ return -1;
+ return conn->write_alerts;
+}
+
+
+int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
+ const struct tls_connection_params *params)
+{
+ int ret;
+ unsigned long err;
+
+ if (conn == NULL)
+ return -1;
+
+ while ((err = ERR_get_error())) {
+ wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s",
+ __func__, ERR_error_string(err, NULL));
}
- if (data_len == 0) {
- conn->ssl->hello_extension = OPENSSL_malloc(1);
- conn->ssl->hello_extension_len = 0;
- return 0;
+
+ if (tls_connection_set_subject_match(tls_ctx, conn,
+ params->subject_match,
+ params->altsubject_match))
+ return -1;
+ if (tls_connection_ca_cert(tls_ctx, conn, params->ca_cert,
+ params->ca_cert_blob,
+ params->ca_cert_blob_len,
+ params->ca_path))
+ return -1;
+ if (tls_connection_client_cert(tls_ctx, conn, params->client_cert,
+ params->client_cert_blob,
+ params->client_cert_blob_len))
+ return -1;
+
+ if (params->engine) {
+ wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine");
+ ret = tls_engine_init(conn, params->engine_id, params->pin,
+ params->key_id);
+ if (ret)
+ return ret;
+ if (tls_connection_engine_private_key(tls_ctx, conn))
+ return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
+ } else if (tls_connection_private_key(tls_ctx, conn,
+ params->private_key,
+ params->private_key_passwd,
+ params->private_key_blob,
+ params->private_key_blob_len)) {
+ wpa_printf(MSG_INFO, "TLS: Failed to load private key '%s'",
+ params->private_key);
+ return -1;
}
- conn->ssl->hello_extension = OPENSSL_malloc(sizeof(*hdr) + data_len);
- if (conn->ssl->hello_extension == NULL)
+
+ if (tls_connection_dh(tls_ctx, conn, params->dh_file)) {
+ wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'",
+ params->dh_file);
return -1;
+ }
- hdr = (struct tls_ext_hdr *) conn->ssl->hello_extension;
- hdr->extensions_len = host_to_be16(sizeof(*hdr) - 2 + data_len);
- hdr->extension_type = host_to_be16(ext_type);
- hdr->extension_len = host_to_be16(data_len);
- memcpy(hdr + 1, data, data_len);
- conn->ssl->hello_extension_len = sizeof(*hdr) + data_len;
+ tls_get_errors(tls_ctx);
return 0;
}
-#endif /* EAP_FAST */
+
+
+int tls_connection_get_keyblock_size(void *tls_ctx,
+ struct tls_connection *conn)
+{
+ const EVP_CIPHER *c;
+ const EVP_MD *h;
+
+ if (conn == NULL || conn->ssl == NULL ||
+ conn->ssl->enc_read_ctx == NULL ||
+ conn->ssl->enc_read_ctx->cipher == NULL ||
+ conn->ssl->read_hash == NULL)
+ return -1;
+
+ c = conn->ssl->enc_read_ctx->cipher;
+ h = conn->ssl->read_hash;
+
+ return 2 * (EVP_CIPHER_key_length(c) +
+ EVP_MD_size(h) +
+ EVP_CIPHER_iv_length(c));
+}
diff --git a/contrib/hostapd/version.h b/contrib/hostapd/version.h
index b030f34b94f9..8f8eff860b87 100644
--- a/contrib/hostapd/version.h
+++ b/contrib/hostapd/version.h
@@ -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 */
diff --git a/contrib/hostapd/wired.conf b/contrib/hostapd/wired.conf
index d1f3c4e3ed22..956f8c53c540 100644
--- a/contrib/hostapd/wired.conf
+++ b/contrib/hostapd/wired.conf
@@ -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
diff --git a/contrib/hostapd/wpa.c b/contrib/hostapd/wpa.c
index b0e42c23bf26..4bac473122d6 100644
--- a/contrib/hostapd/wpa.c
+++ b/contrib/hostapd/wpa.c
@@ -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);
}
diff --git a/contrib/hostapd/wpa.h b/contrib/hostapd/wpa.h
index 929e4a810030..62159e78cfab 100644
--- a/contrib/hostapd/wpa.h
+++ b/contrib/hostapd/wpa.h
@@ -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,
diff --git a/contrib/hostapd/wpa_ctrl.c b/contrib/hostapd/wpa_ctrl.c
new file mode 100644
index 000000000000..98e0669a4738
--- /dev/null
+++ b/contrib/hostapd/wpa_ctrl.c
@@ -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;
+}
diff --git a/contrib/hostapd/wpa_ctrl.h b/contrib/hostapd/wpa_ctrl.h
new file mode 100644
index 000000000000..c8fa48d69385
--- /dev/null
+++ b/contrib/hostapd/wpa_ctrl.h
@@ -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 */