aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--hostapd/Android.mk4
-rw-r--r--hostapd/Makefile11
-rw-r--r--hostapd/hlr_auc_gw.c5
-rw-r--r--hostapd/hlr_auc_gw.txt8
-rw-r--r--hostapd/hostapd.conf4
-rw-r--r--src/ap/hw_features.c2
-rw-r--r--src/ap/wpa_auth.c129
-rw-r--r--src/ap/wpa_auth_ft.c13
-rw-r--r--src/ap/wpa_auth_ie.c130
-rw-r--r--src/common/wpa_common.c135
-rw-r--r--src/common/wpa_common.h8
-rw-r--r--src/drivers/driver_atheros.c3
-rw-r--r--src/eap_peer/eap.c13
-rw-r--r--src/eap_peer/eap.h11
-rw-r--r--src/eap_peer/eap_aka.c32
-rw-r--r--src/eap_peer/eap_config.h3
-rw-r--r--src/eap_peer/eap_sim.c42
-rw-r--r--src/eap_server/eap_i.h2
-rw-r--r--src/eap_server/eap_server_aka.c347
-rw-r--r--src/eap_server/eap_server_sim.c253
-rw-r--r--src/eap_server/eap_sim_db.c930
-rw-r--r--src/eap_server/eap_sim_db.h67
-rw-r--r--src/eapol_supp/eapol_supp_sm.c12
-rw-r--r--src/eapol_supp/eapol_supp_sm.h8
-rw-r--r--src/p2p/p2p_invitation.c7
-rw-r--r--src/rsn_supp/peerkey.c25
-rw-r--r--src/rsn_supp/wpa.c201
-rw-r--r--src/rsn_supp/wpa_ft.c71
-rw-r--r--src/rsn_supp/wpa_ie.c54
-rw-r--r--wpa_supplicant/Android.mk1
-rw-r--r--wpa_supplicant/bss.c77
-rw-r--r--wpa_supplicant/bss.h38
-rw-r--r--wpa_supplicant/ctrl_iface.c24
-rw-r--r--wpa_supplicant/eapol_test.c32
-rw-r--r--wpa_supplicant/events.c4
-rw-r--r--wpa_supplicant/hs20_supplicant.c28
-rw-r--r--wpa_supplicant/interworking.c282
-rw-r--r--wpa_supplicant/wpa_supplicant.conf3
-rw-r--r--wpa_supplicant/wpa_supplicant_i.h1
-rw-r--r--wpa_supplicant/wpas_glue.c41
40 files changed, 1718 insertions, 1343 deletions
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index ed9f654..ee153d0 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -532,6 +532,10 @@ ifeq ($(CONFIG_TLS), gnutls)
ifdef TLS_FUNCS
OBJS += src/crypto/tls_gnutls.c
LIBS += -lgnutls -lgpg-error
+ifdef CONFIG_GNUTLS_EXTRA
+L_CFLAGS += -DCONFIG_GNUTLS_EXTRA
+LIBS += -lgnutls-extra
+endif
endif
OBJS += src/crypto/crypto_gnutls.c
HOBJS += src/crypto/crypto_gnutls.c
diff --git a/hostapd/Makefile b/hostapd/Makefile
index 6809b07..f5dfce0 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -825,6 +825,12 @@ ifdef CONFIG_DEBUG_FILE
CFLAGS += -DCONFIG_DEBUG_FILE
endif
+ifdef CONFIG_SQLITE
+CFLAGS += -DCONFIG_SQLITE
+LIBS += -lsqlite3
+LIBS_h += -lsqlite3
+endif
+
ALL=hostapd hostapd_cli
all: verify_config $(ALL)
@@ -892,11 +898,6 @@ ifdef TLS_FUNCS
LIBS_n += -lcrypto
endif
-ifdef CONFIG_SQLITE
-CFLAGS += -DCONFIG_SQLITE
-LIBS_h += -lsqlite3
-endif
-
HOBJS += hlr_auc_gw.o ../src/utils/common.o ../src/utils/wpa_debug.o ../src/utils/os_$(CONFIG_OS).o ../src/utils/wpabuf.o ../src/crypto/milenage.o
HOBJS += ../src/crypto/aes-encblock.o
ifdef CONFIG_INTERNAL_AES
diff --git a/hostapd/hlr_auc_gw.c b/hostapd/hlr_auc_gw.c
index e27ddab..e04e2e9 100644
--- a/hostapd/hlr_auc_gw.c
+++ b/hostapd/hlr_auc_gw.c
@@ -78,6 +78,7 @@ struct milenage_parameters {
u8 opc[16];
u8 amf[2];
u8 sqn[6];
+ int set;
};
static struct milenage_parameters *milenage_db = NULL;
@@ -155,6 +156,8 @@ static int get_milenage_cb(void *ctx, int argc, char *argv[], char *col[])
struct milenage_parameters *m = ctx;
int i;
+ m->set = 1;
+
for (i = 0; i < argc; i++) {
if (os_strcmp(col[i], "ki") == 0 && argv[i] &&
hexstr2bin(argv[i], m->ki, sizeof(m->ki))) {
@@ -201,6 +204,8 @@ static struct milenage_parameters * db_get_milenage(const char *imsi_txt)
NULL) != SQLITE_OK)
return NULL;
+ if (!db_tmp_milenage.set)
+ return NULL;
return &db_tmp_milenage;
}
diff --git a/hostapd/hlr_auc_gw.txt b/hostapd/hlr_auc_gw.txt
index e4b6783..097bbce 100644
--- a/hostapd/hlr_auc_gw.txt
+++ b/hostapd/hlr_auc_gw.txt
@@ -63,6 +63,12 @@ INSERT INTO milenage(imsi,ki,opc,amf,sqn) VALUES(
);
+hostapd (EAP server) can also be configured to store the EAP-SIM/AKA
+pseudonyms and reauth information into a SQLite database. This is
+configured with the db parameter within the eap_sim_db configuration
+option.
+
+
"hlr_auc_gw -D /path/to/hlr_auc_gw.db" can then be used to fetch
Milenage parameters based on IMSI from the database. The database can be
updated dynamically while hlr_auc_gw is running to add/remove/modify
@@ -78,7 +84,7 @@ driver=none
radius_server_clients=hostapd.radius_clients
eap_server=1
eap_user_file=hostapd.eap_user
-eap_sim_db=unix:/tmp/hlr_auc_gw.sock
+eap_sim_db=unix:/tmp/hlr_auc_gw.sock db=/tmp/eap_sim.db
eap_sim_aka_result_ind=1
hostapd.radius_clients:
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 5a2c2ea..edbd772 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -681,8 +681,10 @@ eap_server=0
# This is a text string in implementation specific format. The example
# implementation in eap_sim_db.c uses this as the UNIX domain socket name for
# the HLR/AuC gateway (e.g., hlr_auc_gw). In this case, the path uses "unix:"
-# prefix.
+# prefix. If hostapd is built with SQLite support (CONFIG_SQLITE=y in .config),
+# database file can be described with an optional db=<path> parameter.
#eap_sim_db=unix:/tmp/hlr_auc_gw.sock
+#eap_sim_db=unix:/tmp/hlr_auc_gw.sock db=/tmp/hostapd.db
# Encryption key for EAP-FAST PAC-Opaque values. This key must be a secret,
# random value. It is configured as a 16-octet value in hex format. It can be
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 76aff77..97e1238 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -129,6 +129,8 @@ int hostapd_prepare_rates(struct hostapd_iface *iface,
i = 0;
while (basic_rates[i] >= 0)
i++;
+ if (i)
+ i++; /* -1 termination */
os_free(iface->basic_rates);
iface->basic_rates = os_malloc(i * sizeof(int));
if (iface->basic_rates)
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 3203d4f..49d8175 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -278,28 +278,6 @@ static void wpa_auth_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry,
}
-static void wpa_group_set_key_len(struct wpa_group *group, int cipher)
-{
- switch (cipher) {
- case WPA_CIPHER_CCMP:
- group->GTK_len = 16;
- break;
- case WPA_CIPHER_GCMP:
- group->GTK_len = 16;
- break;
- case WPA_CIPHER_TKIP:
- group->GTK_len = 32;
- break;
- case WPA_CIPHER_WEP104:
- group->GTK_len = 13;
- break;
- case WPA_CIPHER_WEP40:
- group->GTK_len = 5;
- break;
- }
-}
-
-
static int wpa_group_init_gmk_and_counter(struct wpa_authenticator *wpa_auth,
struct wpa_group *group)
{
@@ -341,8 +319,7 @@ static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
group->GTKAuthenticator = TRUE;
group->vlan_id = vlan_id;
-
- wpa_group_set_key_len(group, wpa_auth->conf.wpa_group);
+ group->GTK_len = wpa_cipher_key_len(wpa_auth->conf.wpa_group);
if (random_pool_ready() != 1) {
wpa_printf(MSG_INFO, "WPA: Not enough entropy in random pool "
@@ -517,7 +494,7 @@ int wpa_reconfig(struct wpa_authenticator *wpa_auth,
* configuration.
*/
group = wpa_auth->group;
- wpa_group_set_key_len(group, wpa_auth->conf.wpa_group);
+ group->GTK_len = wpa_cipher_key_len(wpa_auth->conf.wpa_group);
group->GInit = TRUE;
wpa_group_sm_step(wpa_auth, group);
group->GInit = FALSE;
@@ -1291,23 +1268,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
WPA_PUT_BE16(key->key_info, key_info);
alg = pairwise ? sm->pairwise : wpa_auth->conf.wpa_group;
- switch (alg) {
- case WPA_CIPHER_CCMP:
- WPA_PUT_BE16(key->key_length, 16);
- break;
- case WPA_CIPHER_GCMP:
- WPA_PUT_BE16(key->key_length, 16);
- break;
- case WPA_CIPHER_TKIP:
- WPA_PUT_BE16(key->key_length, 32);
- break;
- case WPA_CIPHER_WEP40:
- WPA_PUT_BE16(key->key_length, 5);
- break;
- case WPA_CIPHER_WEP104:
- WPA_PUT_BE16(key->key_length, 13);
- break;
- }
+ WPA_PUT_BE16(key->key_length, wpa_cipher_key_len(alg));
if (key_info & WPA_KEY_INFO_SMK_MESSAGE)
WPA_PUT_BE16(key->key_length, 0);
@@ -1540,24 +1501,6 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event)
}
-static enum wpa_alg wpa_alg_enum(int alg)
-{
- switch (alg) {
- case WPA_CIPHER_CCMP:
- return WPA_ALG_CCMP;
- case WPA_CIPHER_GCMP:
- return WPA_ALG_GCMP;
- case WPA_CIPHER_TKIP:
- return WPA_ALG_TKIP;
- case WPA_CIPHER_WEP104:
- case WPA_CIPHER_WEP40:
- return WPA_ALG_WEP;
- default:
- return WPA_ALG_NONE;
- }
-}
-
-
SM_STATE(WPA_PTK, INITIALIZE)
{
SM_ENTRY_MA(WPA_PTK, INITIALIZE, wpa_ptk);
@@ -2097,18 +2040,8 @@ SM_STATE(WPA_PTK, PTKINITDONE)
SM_ENTRY_MA(WPA_PTK, PTKINITDONE, wpa_ptk);
sm->EAPOLKeyReceived = FALSE;
if (sm->Pair) {
- enum wpa_alg alg;
- int klen;
- if (sm->pairwise == WPA_CIPHER_TKIP) {
- alg = WPA_ALG_TKIP;
- klen = 32;
- } else if (sm->pairwise == WPA_CIPHER_GCMP) {
- alg = WPA_ALG_GCMP;
- klen = 16;
- } else {
- alg = WPA_ALG_CCMP;
- klen = 16;
- }
+ enum wpa_alg alg = wpa_cipher_to_alg(sm->pairwise);
+ int klen = wpa_cipher_key_len(sm->pairwise);
if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
sm->PTK.tk1, klen)) {
wpa_sta_disconnect(sm->wpa_auth, sm->addr);
@@ -2657,7 +2590,7 @@ static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
int ret = 0;
if (wpa_auth_set_key(wpa_auth, group->vlan_id,
- wpa_alg_enum(wpa_auth->conf.wpa_group),
+ wpa_cipher_to_alg(wpa_auth->conf.wpa_group),
broadcast_ether_addr, group->GN,
group->GTK[group->GN - 1], group->GTK_len) < 0)
ret = -1;
@@ -2797,25 +2730,6 @@ static const char * wpa_bool_txt(int bool)
}
-static int wpa_cipher_bits(int cipher)
-{
- switch (cipher) {
- case WPA_CIPHER_CCMP:
- return 128;
- case WPA_CIPHER_GCMP:
- return 128;
- case WPA_CIPHER_TKIP:
- return 256;
- case WPA_CIPHER_WEP104:
- return 104;
- case WPA_CIPHER_WEP40:
- return 40;
- default:
- return 0;
- }
-}
-
-
#define RSN_SUITE "%02x-%02x-%02x-%d"
#define RSN_SUITE_ARG(s) \
((s) >> 24) & 0xff, ((s) >> 16) & 0xff, ((s) >> 8) & 0xff, (s) & 0xff
@@ -2878,7 +2792,7 @@ int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen)
!!wpa_auth->conf.wpa_strict_rekey,
dot11RSNAConfigGroupUpdateCount,
dot11RSNAConfigPairwiseUpdateCount,
- wpa_cipher_bits(wpa_auth->conf.wpa_group),
+ wpa_cipher_key_len(wpa_auth->conf.wpa_group) * 8,
dot11RSNAConfigPMKLifetime,
dot11RSNAConfigPMKReauthThreshold,
dot11RSNAConfigSATimeout,
@@ -2921,31 +2835,10 @@ int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen)
/* dot11RSNAStatsEntry */
- if (sm->wpa == WPA_VERSION_WPA) {
- if (sm->pairwise == WPA_CIPHER_CCMP)
- pairwise = WPA_CIPHER_SUITE_CCMP;
- else if (sm->pairwise == WPA_CIPHER_TKIP)
- pairwise = WPA_CIPHER_SUITE_TKIP;
- else if (sm->pairwise == WPA_CIPHER_WEP104)
- pairwise = WPA_CIPHER_SUITE_WEP104;
- else if (sm->pairwise == WPA_CIPHER_WEP40)
- pairwise = WPA_CIPHER_SUITE_WEP40;
- else if (sm->pairwise == WPA_CIPHER_NONE)
- pairwise = WPA_CIPHER_SUITE_NONE;
- } else if (sm->wpa == WPA_VERSION_WPA2) {
- if (sm->pairwise == WPA_CIPHER_CCMP)
- pairwise = RSN_CIPHER_SUITE_CCMP;
- else if (sm->pairwise == WPA_CIPHER_GCMP)
- pairwise = RSN_CIPHER_SUITE_GCMP;
- else if (sm->pairwise == WPA_CIPHER_TKIP)
- pairwise = RSN_CIPHER_SUITE_TKIP;
- else if (sm->pairwise == WPA_CIPHER_WEP104)
- pairwise = RSN_CIPHER_SUITE_WEP104;
- else if (sm->pairwise == WPA_CIPHER_WEP40)
- pairwise = RSN_CIPHER_SUITE_WEP40;
- else if (sm->pairwise == WPA_CIPHER_NONE)
- pairwise = RSN_CIPHER_SUITE_NONE;
- } else
+ pairwise = wpa_cipher_to_suite(sm->wpa == WPA_VERSION_WPA2 ?
+ WPA_PROTO_RSN : WPA_PROTO_WPA,
+ sm->pairwise);
+ if (pairwise == 0)
return 0;
ret = os_snprintf(
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index 9f7cdae..48bf79b 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -754,16 +754,9 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm)
int klen;
/* MLME-SETKEYS.request(PTK) */
- if (sm->pairwise == WPA_CIPHER_TKIP) {
- alg = WPA_ALG_TKIP;
- klen = 32;
- } else if (sm->pairwise == WPA_CIPHER_CCMP) {
- alg = WPA_ALG_CCMP;
- klen = 16;
- } else if (sm->pairwise == WPA_CIPHER_GCMP) {
- alg = WPA_ALG_GCMP;
- klen = 16;
- } else {
+ alg = wpa_cipher_to_alg(sm->pairwise);
+ klen = wpa_cipher_key_len(sm->pairwise);
+ if (!wpa_cipher_valid_pairwise(sm->pairwise)) {
wpa_printf(MSG_DEBUG, "FT: Unknown pairwise alg 0x%x - skip "
"PTK configuration", sm->pairwise);
return;
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index b88b80a..1786230 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -29,6 +29,7 @@ static int wpa_write_wpa_ie(struct wpa_auth_config *conf, u8 *buf, size_t len)
struct wpa_ie_hdr *hdr;
int num_suites;
u8 *pos, *count;
+ u32 suite;
hdr = (struct wpa_ie_hdr *) buf;
hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC;
@@ -36,46 +37,25 @@ static int wpa_write_wpa_ie(struct wpa_auth_config *conf, u8 *buf, size_t len)
WPA_PUT_LE16(hdr->version, WPA_VERSION);
pos = (u8 *) (hdr + 1);
- if (conf->wpa_group == WPA_CIPHER_CCMP) {
- RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
- } else if (conf->wpa_group == WPA_CIPHER_TKIP) {
- RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
- } else if (conf->wpa_group == WPA_CIPHER_WEP104) {
- RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP104);
- } else if (conf->wpa_group == WPA_CIPHER_WEP40) {
- RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP40);
- } else {
+ suite = wpa_cipher_to_suite(WPA_PROTO_WPA, conf->wpa_group);
+ if (suite == 0) {
wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).",
conf->wpa_group);
return -1;
}
+ RSN_SELECTOR_PUT(pos, suite);
pos += WPA_SELECTOR_LEN;
- num_suites = 0;
count = pos;
pos += 2;
- if (conf->wpa_pairwise & WPA_CIPHER_CCMP) {
- RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
- pos += WPA_SELECTOR_LEN;
- num_suites++;
- }
- if (conf->wpa_pairwise & WPA_CIPHER_TKIP) {
- RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
- pos += WPA_SELECTOR_LEN;
- num_suites++;
- }
- if (conf->wpa_pairwise & WPA_CIPHER_NONE) {
- RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE);
- pos += WPA_SELECTOR_LEN;
- num_suites++;
- }
-
+ num_suites = wpa_cipher_put_suites(pos, conf->wpa_pairwise);
if (num_suites == 0) {
wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).",
conf->wpa_pairwise);
return -1;
}
+ pos += num_suites * WPA_SELECTOR_LEN;
WPA_PUT_LE16(count, num_suites);
num_suites = 0;
@@ -112,30 +92,23 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
const u8 *pmkid)
{
struct rsn_ie_hdr *hdr;
- int num_suites;
+ int num_suites, res;
u8 *pos, *count;
u16 capab;
+ u32 suite;
hdr = (struct rsn_ie_hdr *) buf;
hdr->elem_id = WLAN_EID_RSN;
WPA_PUT_LE16(hdr->version, RSN_VERSION);
pos = (u8 *) (hdr + 1);
- if (conf->wpa_group == WPA_CIPHER_CCMP) {
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
- } else if (conf->wpa_group == WPA_CIPHER_GCMP) {
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP);
- } else if (conf->wpa_group == WPA_CIPHER_TKIP) {
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
- } else if (conf->wpa_group == WPA_CIPHER_WEP104) {
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP104);
- } else if (conf->wpa_group == WPA_CIPHER_WEP40) {
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP40);
- } else {
+ suite = wpa_cipher_to_suite(WPA_PROTO_RSN, conf->wpa_group);
+ if (suite == 0) {
wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).",
conf->wpa_group);
return -1;
}
+ RSN_SELECTOR_PUT(pos, suite);
pos += RSN_SELECTOR_LEN;
num_suites = 0;
@@ -150,26 +123,9 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
}
#endif /* CONFIG_RSN_TESTING */
- if (conf->rsn_pairwise & WPA_CIPHER_CCMP) {
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
- pos += RSN_SELECTOR_LEN;
- num_suites++;
- }
- if (conf->rsn_pairwise & WPA_CIPHER_GCMP) {
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP);
- pos += RSN_SELECTOR_LEN;
- num_suites++;
- }
- if (conf->rsn_pairwise & WPA_CIPHER_TKIP) {
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
- pos += RSN_SELECTOR_LEN;
- num_suites++;
- }
- if (conf->rsn_pairwise & WPA_CIPHER_NONE) {
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE);
- pos += RSN_SELECTOR_LEN;
- num_suites++;
- }
+ res = rsn_cipher_put_suites(pos, conf->rsn_pairwise);
+ num_suites += res;
+ pos += res * RSN_SELECTOR_LEN;
#ifdef CONFIG_RSN_TESTING
if (rsn_testing) {
@@ -457,34 +413,16 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
selector = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector;
- selector = RSN_CIPHER_SUITE_CCMP;
- if (data.pairwise_cipher & WPA_CIPHER_CCMP)
+ selector = wpa_cipher_to_suite(WPA_PROTO_RSN,
+ data.pairwise_cipher);
+ if (!selector)
selector = RSN_CIPHER_SUITE_CCMP;
- else if (data.pairwise_cipher & WPA_CIPHER_GCMP)
- selector = RSN_CIPHER_SUITE_GCMP;
- else if (data.pairwise_cipher & WPA_CIPHER_TKIP)
- selector = RSN_CIPHER_SUITE_TKIP;
- else if (data.pairwise_cipher & WPA_CIPHER_WEP104)
- selector = RSN_CIPHER_SUITE_WEP104;
- else if (data.pairwise_cipher & WPA_CIPHER_WEP40)
- selector = RSN_CIPHER_SUITE_WEP40;
- else if (data.pairwise_cipher & WPA_CIPHER_NONE)
- selector = RSN_CIPHER_SUITE_NONE;
wpa_auth->dot11RSNAPairwiseCipherSelected = selector;
- selector = RSN_CIPHER_SUITE_CCMP;
- if (data.group_cipher & WPA_CIPHER_CCMP)
+ selector = wpa_cipher_to_suite(WPA_PROTO_RSN,
+ data.group_cipher);
+ if (!selector)
selector = RSN_CIPHER_SUITE_CCMP;
- else if (data.group_cipher & WPA_CIPHER_GCMP)
- selector = RSN_CIPHER_SUITE_GCMP;
- else if (data.group_cipher & WPA_CIPHER_TKIP)
- selector = RSN_CIPHER_SUITE_TKIP;
- else if (data.group_cipher & WPA_CIPHER_WEP104)
- selector = RSN_CIPHER_SUITE_WEP104;
- else if (data.group_cipher & WPA_CIPHER_WEP40)
- selector = RSN_CIPHER_SUITE_WEP40;
- else if (data.group_cipher & WPA_CIPHER_NONE)
- selector = RSN_CIPHER_SUITE_NONE;
wpa_auth->dot11RSNAGroupCipherSelected = selector;
} else {
res = wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, &data);
@@ -496,30 +434,16 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
selector = WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X;
wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector;
- selector = WPA_CIPHER_SUITE_TKIP;
- if (data.pairwise_cipher & WPA_CIPHER_CCMP)
- selector = WPA_CIPHER_SUITE_CCMP;
- else if (data.pairwise_cipher & WPA_CIPHER_TKIP)
- selector = WPA_CIPHER_SUITE_TKIP;
- else if (data.pairwise_cipher & WPA_CIPHER_WEP104)
- selector = WPA_CIPHER_SUITE_WEP104;
- else if (data.pairwise_cipher & WPA_CIPHER_WEP40)
- selector = WPA_CIPHER_SUITE_WEP40;
- else if (data.pairwise_cipher & WPA_CIPHER_NONE)
- selector = WPA_CIPHER_SUITE_NONE;
+ selector = wpa_cipher_to_suite(WPA_PROTO_WPA,
+ data.pairwise_cipher);
+ if (!selector)
+ selector = RSN_CIPHER_SUITE_TKIP;
wpa_auth->dot11RSNAPairwiseCipherSelected = selector;
- selector = WPA_CIPHER_SUITE_TKIP;
- if (data.group_cipher & WPA_CIPHER_CCMP)
- selector = WPA_CIPHER_SUITE_CCMP;
- else if (data.group_cipher & WPA_CIPHER_TKIP)
+ selector = wpa_cipher_to_suite(WPA_PROTO_WPA,
+ data.group_cipher);
+ if (!selector)
selector = WPA_CIPHER_SUITE_TKIP;
- else if (data.group_cipher & WPA_CIPHER_WEP104)
- selector = WPA_CIPHER_SUITE_WEP104;
- else if (data.group_cipher & WPA_CIPHER_WEP40)
- selector = WPA_CIPHER_SUITE_WEP40;
- else if (data.group_cipher & WPA_CIPHER_NONE)
- selector = WPA_CIPHER_SUITE_NONE;
wpa_auth->dot11RSNAGroupCipherSelected = selector;
}
if (res) {
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index 36febb3..36c308a 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -1073,3 +1073,138 @@ int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid)
return added;
}
#endif /* CONFIG_IEEE80211R */
+
+
+int wpa_cipher_key_len(int cipher)
+{
+ switch (cipher) {
+ case WPA_CIPHER_CCMP:
+ case WPA_CIPHER_GCMP:
+ return 16;
+ case WPA_CIPHER_TKIP:
+ return 32;
+ case WPA_CIPHER_WEP104:
+ return 13;
+ case WPA_CIPHER_WEP40:
+ return 5;
+ }
+
+ return 0;
+}
+
+
+int wpa_cipher_rsc_len(int cipher)
+{
+ switch (cipher) {
+ case WPA_CIPHER_CCMP:
+ case WPA_CIPHER_GCMP:
+ case WPA_CIPHER_TKIP:
+ return 6;
+ case WPA_CIPHER_WEP104:
+ case WPA_CIPHER_WEP40:
+ return 0;
+ }
+
+ return 0;
+}
+
+
+int wpa_cipher_to_alg(int cipher)
+{
+ switch (cipher) {
+ case WPA_CIPHER_CCMP:
+ return WPA_ALG_CCMP;
+ case WPA_CIPHER_GCMP:
+ return WPA_ALG_GCMP;
+ case WPA_CIPHER_TKIP:
+ return WPA_ALG_TKIP;
+ case WPA_CIPHER_WEP104:
+ case WPA_CIPHER_WEP40:
+ return WPA_ALG_WEP;
+ }
+ return WPA_ALG_NONE;
+}
+
+
+int wpa_cipher_valid_pairwise(int cipher)
+{
+ return cipher == WPA_CIPHER_CCMP ||
+ cipher == WPA_CIPHER_GCMP ||
+ cipher == WPA_CIPHER_TKIP;
+}
+
+
+u32 wpa_cipher_to_suite(int proto, int cipher)
+{
+ if (cipher & WPA_CIPHER_CCMP)
+ return (proto == WPA_PROTO_RSN ?
+ RSN_CIPHER_SUITE_CCMP : WPA_CIPHER_SUITE_CCMP);
+ if (cipher & WPA_CIPHER_GCMP)
+ return RSN_CIPHER_SUITE_GCMP;
+ if (cipher & WPA_CIPHER_TKIP)
+ return (proto == WPA_PROTO_RSN ?
+ RSN_CIPHER_SUITE_TKIP : WPA_CIPHER_SUITE_TKIP);
+ if (cipher & WPA_CIPHER_WEP104)
+ return (proto == WPA_PROTO_RSN ?
+ RSN_CIPHER_SUITE_WEP104 : WPA_CIPHER_SUITE_WEP104);
+ if (cipher & WPA_CIPHER_WEP40)
+ return (proto == WPA_PROTO_RSN ?
+ RSN_CIPHER_SUITE_WEP40 : WPA_CIPHER_SUITE_WEP40);
+ if (cipher & WPA_CIPHER_NONE)
+ return (proto == WPA_PROTO_RSN ?
+ RSN_CIPHER_SUITE_NONE : WPA_CIPHER_SUITE_NONE);
+ return 0;
+}
+
+
+int rsn_cipher_put_suites(u8 *pos, int ciphers)
+{
+ int num_suites = 0;
+
+ if (ciphers & WPA_CIPHER_CCMP) {
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+ if (ciphers & WPA_CIPHER_GCMP) {
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+ if (ciphers & WPA_CIPHER_TKIP) {
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+ if (ciphers & WPA_CIPHER_NONE) {
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+
+ return num_suites;
+}
+
+
+int wpa_cipher_put_suites(u8 *pos, int ciphers)
+{
+ int num_suites = 0;
+
+ if (ciphers & WPA_CIPHER_CCMP) {
+ RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
+ pos += WPA_SELECTOR_LEN;
+ num_suites++;
+ }
+ if (ciphers & WPA_CIPHER_TKIP) {
+ RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
+ pos += WPA_SELECTOR_LEN;
+ num_suites++;
+ }
+ if (ciphers & WPA_CIPHER_NONE) {
+ RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE);
+ pos += WPA_SELECTOR_LEN;
+ num_suites++;
+ }
+
+ return num_suites;
+}
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index c871ae1..603166b 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -379,4 +379,12 @@ struct wpa_ft_ies {
int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse);
+int wpa_cipher_key_len(int cipher);
+int wpa_cipher_rsc_len(int cipher);
+int wpa_cipher_to_alg(int cipher);
+int wpa_cipher_valid_pairwise(int cipher);
+u32 wpa_cipher_to_suite(int proto, int cipher);
+int rsn_cipher_put_suites(u8 *pos, int ciphers);
+int wpa_cipher_put_suites(u8 *pos, int ciphers);
+
#endif /* WPA_COMMON_H */
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index fefae8c..5f2e675 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -324,8 +324,7 @@ atheros_configure_wpa(struct atheros_driver_data *drv,
}
#endif /* CONFIG_IEEE80211W */
- wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x",
- __func__, params->rsn_preauth);
+ wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x", __func__, v);
if (set80211param(drv, IEEE80211_PARAM_RSNCAPS, v)) {
printf("Unable to set RSN capabilities to 0x%x\n", v);
return -1;
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index ba973a5..2ed74b8 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -2321,3 +2321,16 @@ void eap_sm_set_ext_pw_ctx(struct eap_sm *sm, struct ext_password_data *ext)
sm->ext_pw_buf = NULL;
sm->ext_pw = ext;
}
+
+
+/**
+ * eap_set_anon_id - Set or add anonymous identity
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @id: Anonymous identity (e.g., EAP-SIM pseudonym) or %NULL to clear
+ * @len: Length of anonymous identity in octets
+ */
+void eap_set_anon_id(struct eap_sm *sm, const u8 *id, size_t len)
+{
+ if (sm->eapol_cb->set_anon_id)
+ sm->eapol_cb->set_anon_id(sm->eapol_ctx, id, len);
+}
diff --git a/src/eap_peer/eap.h b/src/eap_peer/eap.h
index cf58608..8bccef1 100644
--- a/src/eap_peer/eap.h
+++ b/src/eap_peer/eap.h
@@ -1,6 +1,6 @@
/*
* EAP peer state machine functions (RFC 4137)
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -235,6 +235,14 @@ struct eapol_callbacks {
*/
void (*notify_status)(void *ctx, const char *status,
const char *parameter);
+
+ /**
+ * set_anon_id - Set or add anonymous identity
+ * @ctx: eapol_ctx from eap_peer_sm_init() call
+ * @id: Anonymous identity (e.g., EAP-SIM pseudonym) or %NULL to clear
+ * @len: Length of anonymous identity in octets
+ */
+ void (*set_anon_id)(void *ctx, const u8 *id, size_t len);
};
/**
@@ -308,6 +316,7 @@ int eap_is_wps_pin_enrollee(struct eap_peer_config *conf);
struct ext_password_data;
void eap_sm_set_ext_pw_ctx(struct eap_sm *sm, struct ext_password_data *ext);
+void eap_set_anon_id(struct eap_sm *sm, const u8 *id, size_t len);
#endif /* IEEE8021X_EAPOL */
diff --git a/src/eap_peer/eap_aka.c b/src/eap_peer/eap_aka.c
index 1cec4d8..59861cb 100644
--- a/src/eap_peer/eap_aka.c
+++ b/src/eap_peer/eap_aka.c
@@ -90,6 +90,7 @@ static void * eap_aka_init(struct eap_sm *sm)
{
struct eap_aka_data *data;
const char *phase1 = eap_get_config_phase1(sm);
+ struct eap_peer_config *config = eap_get_config(sm);
data = os_zalloc(sizeof(*data));
if (data == NULL)
@@ -102,6 +103,15 @@ static void * eap_aka_init(struct eap_sm *sm)
data->result_ind = phase1 && os_strstr(phase1, "result_ind=1") != NULL;
+ if (config && config->anonymous_identity) {
+ data->pseudonym = os_malloc(config->anonymous_identity_len);
+ if (data->pseudonym) {
+ os_memcpy(data->pseudonym, config->anonymous_identity,
+ config->anonymous_identity_len);
+ data->pseudonym_len = config->anonymous_identity_len;
+ }
+ }
+
return data;
}
@@ -227,13 +237,15 @@ static int eap_aka_umts_auth(struct eap_sm *sm, struct eap_aka_data *data)
#define CLEAR_REAUTH_ID 0x02
#define CLEAR_EAP_ID 0x04
-static void eap_aka_clear_identities(struct eap_aka_data *data, int id)
+static void eap_aka_clear_identities(struct eap_sm *sm,
+ struct eap_aka_data *data, int id)
{
if ((id & CLEAR_PSEUDONYM) && data->pseudonym) {
wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old pseudonym");
os_free(data->pseudonym);
data->pseudonym = NULL;
data->pseudonym_len = 0;
+ eap_set_anon_id(sm, NULL, 0);
}
if ((id & CLEAR_REAUTH_ID) && data->reauth_id) {
wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old reauth_id");
@@ -288,6 +300,7 @@ static int eap_aka_learn_ids(struct eap_sm *sm, struct eap_aka_data *data,
realm, realm_len);
}
data->pseudonym_len = attr->next_pseudonym_len + realm_len;
+ eap_set_anon_id(sm, data->pseudonym, data->pseudonym_len);
}
if (attr->next_reauth_id) {
@@ -425,6 +438,8 @@ static struct wpabuf * eap_aka_client_error(struct eap_aka_data *data, u8 id,
data->num_id_req = 0;
data->num_notification = 0;
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Send Client-Error (error code %d)",
+ err);
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
EAP_AKA_SUBTYPE_CLIENT_ERROR);
eap_sim_msg_add(msg, EAP_SIM_AT_CLIENT_ERROR_CODE, err, NULL, 0);
@@ -486,16 +501,16 @@ static struct wpabuf * eap_aka_response_identity(struct eap_sm *sm,
data->pseudonym) {
identity = data->pseudonym;
identity_len = data->pseudonym_len;
- eap_aka_clear_identities(data, CLEAR_REAUTH_ID);
+ eap_aka_clear_identities(sm, data, CLEAR_REAUTH_ID);
} else if (id_req != NO_ID_REQ) {
identity = eap_get_config_identity(sm, &identity_len);
if (identity) {
- eap_aka_clear_identities(data, CLEAR_PSEUDONYM |
+ eap_aka_clear_identities(sm, data, CLEAR_PSEUDONYM |
CLEAR_REAUTH_ID);
}
}
if (id_req != NO_ID_REQ)
- eap_aka_clear_identities(data, CLEAR_EAP_ID);
+ eap_aka_clear_identities(sm, data, CLEAR_EAP_ID);
wpa_printf(MSG_DEBUG, "Generating EAP-AKA Identity (id=%d)", id);
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
@@ -898,7 +913,7 @@ static struct wpabuf * eap_aka_process_challenge(struct eap_sm *sm,
* other words, if no new identities are received, full
* authentication will be used on next reauthentication (using
* pseudonym identity or permanent identity). */
- eap_aka_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
+ eap_aka_clear_identities(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
if (attr->encr_data) {
u8 *decrypted;
@@ -1126,7 +1141,7 @@ static struct wpabuf * eap_aka_process_reauthentication(
data->nonce_s, data->mk,
data->msk, data->emsk);
}
- eap_aka_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
+ eap_aka_clear_identities(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
eap_aka_learn_ids(sm, data, &eattr);
if (data->result_ind && attr->result_ind)
@@ -1142,7 +1157,8 @@ static struct wpabuf * eap_aka_process_reauthentication(
if (data->counter > EAP_AKA_MAX_FAST_REAUTHS) {
wpa_printf(MSG_DEBUG, "EAP-AKA: Maximum number of "
"fast reauths performed - force fullauth");
- eap_aka_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
+ eap_aka_clear_identities(sm, data,
+ CLEAR_REAUTH_ID | CLEAR_EAP_ID);
}
os_free(decrypted);
return eap_aka_response_reauth(data, id, 0, data->nonce_s);
@@ -1260,7 +1276,7 @@ static Boolean eap_aka_has_reauth_data(struct eap_sm *sm, void *priv)
static void eap_aka_deinit_for_reauth(struct eap_sm *sm, void *priv)
{
struct eap_aka_data *data = priv;
- eap_aka_clear_identities(data, CLEAR_EAP_ID);
+ eap_aka_clear_identities(sm, data, CLEAR_EAP_ID);
data->prev_id = -1;
wpabuf_free(data->id_msgs);
data->id_msgs = NULL;
diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h
index a08543e..ed90919 100644
--- a/src/eap_peer/eap_config.h
+++ b/src/eap_peer/eap_config.h
@@ -35,6 +35,9 @@ struct eap_peer_config {
*
* If not set, the identity field will be used for both unencrypted and
* protected fields.
+ *
+ * This field can also be used with EAP-SIM/AKA/AKA' to store the
+ * pseudonym identity.
*/
u8 *anonymous_identity;
diff --git a/src/eap_peer/eap_sim.c b/src/eap_peer/eap_sim.c
index fb4ae82..c936a44 100644
--- a/src/eap_peer/eap_sim.c
+++ b/src/eap_peer/eap_sim.c
@@ -1,6 +1,6 @@
/*
* EAP peer method: EAP-SIM (RFC 4186)
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -117,6 +117,15 @@ static void * eap_sim_init(struct eap_sm *sm)
NULL;
}
+ if (config && config->anonymous_identity) {
+ data->pseudonym = os_malloc(config->anonymous_identity_len);
+ if (data->pseudonym) {
+ os_memcpy(data->pseudonym, config->anonymous_identity,
+ config->anonymous_identity_len);
+ data->pseudonym_len = config->anonymous_identity_len;
+ }
+ }
+
eap_sim_state(data, CONTINUE);
return data;
@@ -258,13 +267,15 @@ static int eap_sim_supported_ver(int version)
#define CLEAR_REAUTH_ID 0x02
#define CLEAR_EAP_ID 0x04
-static void eap_sim_clear_identities(struct eap_sim_data *data, int id)
+static void eap_sim_clear_identities(struct eap_sm *sm,
+ struct eap_sim_data *data, int id)
{
if ((id & CLEAR_PSEUDONYM) && data->pseudonym) {
wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old pseudonym");
os_free(data->pseudonym);
data->pseudonym = NULL;
data->pseudonym_len = 0;
+ eap_set_anon_id(sm, NULL, 0);
}
if ((id & CLEAR_REAUTH_ID) && data->reauth_id) {
wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old reauth_id");
@@ -319,6 +330,7 @@ static int eap_sim_learn_ids(struct eap_sm *sm, struct eap_sim_data *data,
realm, realm_len);
}
data->pseudonym_len = attr->next_pseudonym_len + realm_len;
+ eap_set_anon_id(sm, data->pseudonym, data->pseudonym_len);
}
if (attr->next_reauth_id) {
@@ -352,6 +364,8 @@ static struct wpabuf * eap_sim_client_error(struct eap_sim_data *data, u8 id,
data->num_id_req = 0;
data->num_notification = 0;
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Send Client-Error (error code %d)",
+ err);
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM,
EAP_SIM_SUBTYPE_CLIENT_ERROR);
eap_sim_msg_add(msg, EAP_SIM_AT_CLIENT_ERROR_CODE, err, NULL, 0);
@@ -376,16 +390,16 @@ static struct wpabuf * eap_sim_response_start(struct eap_sm *sm,
data->pseudonym) {
identity = data->pseudonym;
identity_len = data->pseudonym_len;
- eap_sim_clear_identities(data, CLEAR_REAUTH_ID);
+ eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID);
} else if (id_req != NO_ID_REQ) {
identity = eap_get_config_identity(sm, &identity_len);
if (identity) {
- eap_sim_clear_identities(data, CLEAR_PSEUDONYM |
+ eap_sim_clear_identities(sm, data, CLEAR_PSEUDONYM |
CLEAR_REAUTH_ID);
}
}
if (id_req != NO_ID_REQ)
- eap_sim_clear_identities(data, CLEAR_EAP_ID);
+ eap_sim_clear_identities(sm, data, CLEAR_EAP_ID);
wpa_printf(MSG_DEBUG, "Generating EAP-SIM Start (id=%d)", id);
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id,
@@ -432,7 +446,8 @@ static struct wpabuf * eap_sim_response_challenge(struct eap_sim_data *data,
static struct wpabuf * eap_sim_response_reauth(struct eap_sim_data *data,
- u8 id, int counter_too_small)
+ u8 id, int counter_too_small,
+ const u8 *nonce_s)
{
struct eap_sim_msg *msg;
unsigned int counter;
@@ -467,7 +482,7 @@ static struct wpabuf * eap_sim_response_reauth(struct eap_sim_data *data,
}
wpa_printf(MSG_DEBUG, " AT_MAC");
eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
- return eap_sim_msg_finish(msg, data->k_aut, data->nonce_s,
+ return eap_sim_msg_finish(msg, data->k_aut, nonce_s,
EAP_SIM_NONCE_S_LEN);
}
@@ -667,7 +682,7 @@ static struct wpabuf * eap_sim_process_challenge(struct eap_sm *sm,
* other words, if no new reauth identity is received, full
* authentication will be used on next reauthentication (using
* pseudonym identity or permanent identity). */
- eap_sim_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
+ eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
if (attr->encr_data) {
u8 *decrypted;
@@ -863,7 +878,7 @@ static struct wpabuf * eap_sim_process_reauthentication(
data->reauth_id = NULL;
data->reauth_id_len = 0;
os_free(decrypted);
- return eap_sim_response_reauth(data, id, 1);
+ return eap_sim_response_reauth(data, id, 1, eattr.nonce_s);
}
data->counter = eattr.counter;
@@ -875,7 +890,7 @@ static struct wpabuf * eap_sim_process_reauthentication(
data->reauth_id, data->reauth_id_len,
data->nonce_s, data->mk, data->msk,
data->emsk);
- eap_sim_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
+ eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
eap_sim_learn_ids(sm, data, &eattr);
if (data->result_ind && attr->result_ind)
@@ -891,10 +906,11 @@ static struct wpabuf * eap_sim_process_reauthentication(
if (data->counter > EAP_SIM_MAX_FAST_REAUTHS) {
wpa_printf(MSG_DEBUG, "EAP-SIM: Maximum number of "
"fast reauths performed - force fullauth");
- eap_sim_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
+ eap_sim_clear_identities(sm, data,
+ CLEAR_REAUTH_ID | CLEAR_EAP_ID);
}
os_free(decrypted);
- return eap_sim_response_reauth(data, id, 0);
+ return eap_sim_response_reauth(data, id, 0, data->nonce_s);
}
@@ -1002,7 +1018,7 @@ static Boolean eap_sim_has_reauth_data(struct eap_sm *sm, void *priv)
static void eap_sim_deinit_for_reauth(struct eap_sm *sm, void *priv)
{
struct eap_sim_data *data = priv;
- eap_sim_clear_identities(data, CLEAR_EAP_ID);
+ eap_sim_clear_identities(sm, data, CLEAR_EAP_ID);
data->use_result_ind = 0;
}
diff --git a/src/eap_server/eap_i.h b/src/eap_server/eap_i.h
index dfb0ff5..f92704a 100644
--- a/src/eap_server/eap_i.h
+++ b/src/eap_server/eap_i.h
@@ -151,7 +151,7 @@ struct eap_sm {
int user_eap_method_index;
int init_phase2;
void *ssl_ctx;
- void *eap_sim_db_priv;
+ struct eap_sim_db_data *eap_sim_db_priv;
Boolean backend_auth;
Boolean update_user;
int eap_server;
diff --git a/src/eap_server/eap_server_aka.c b/src/eap_server/eap_server_aka.c
index 9cd5509..a965cac 100644
--- a/src/eap_server/eap_server_aka.c
+++ b/src/eap_server/eap_server_aka.c
@@ -49,12 +49,12 @@ struct eap_aka_data {
u8 *network_name;
size_t network_name_len;
u16 kdf;
+ int identity_round;
+ char permanent[20]; /* Permanent username */
};
-static void eap_aka_determine_identity(struct eap_sm *sm,
- struct eap_aka_data *data,
- int before_identity, int after_reauth);
+static void eap_aka_fullauth(struct eap_sm *sm, struct eap_aka_data *data);
static const char * eap_aka_state_txt(int state)
@@ -87,6 +87,96 @@ static void eap_aka_state(struct eap_aka_data *data, int state)
}
+static int eap_aka_check_identity_reauth(struct eap_sm *sm,
+ struct eap_aka_data *data,
+ const char *username)
+{
+ if (data->eap_method == EAP_TYPE_AKA_PRIME &&
+ username[0] != EAP_AKA_PRIME_REAUTH_ID_PREFIX)
+ return 0;
+ if (data->eap_method == EAP_TYPE_AKA &&
+ username[0] != EAP_AKA_REAUTH_ID_PREFIX)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Reauth username '%s'", username);
+ data->reauth = eap_sim_db_get_reauth_entry(sm->eap_sim_db_priv,
+ username);
+ if (data->reauth == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown reauth identity - "
+ "request full auth identity");
+ /* Remain in IDENTITY state for another round */
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Using fast re-authentication");
+ os_strlcpy(data->permanent, data->reauth->permanent,
+ sizeof(data->permanent));
+ data->counter = data->reauth->counter;
+ if (data->eap_method == EAP_TYPE_AKA_PRIME) {
+ os_memcpy(data->k_encr, data->reauth->k_encr,
+ EAP_SIM_K_ENCR_LEN);
+ os_memcpy(data->k_aut, data->reauth->k_aut,
+ EAP_AKA_PRIME_K_AUT_LEN);
+ os_memcpy(data->k_re, data->reauth->k_re,
+ EAP_AKA_PRIME_K_RE_LEN);
+ } else {
+ os_memcpy(data->mk, data->reauth->mk, EAP_SIM_MK_LEN);
+ }
+
+ eap_aka_state(data, REAUTH);
+ return 1;
+}
+
+
+static void eap_aka_check_identity(struct eap_sm *sm,
+ struct eap_aka_data *data)
+{
+ char *username;
+
+ /* Check if we already know the identity from EAP-Response/Identity */
+
+ username = sim_get_username(sm->identity, sm->identity_len);
+ if (username == NULL)
+ return;
+
+ if (eap_aka_check_identity_reauth(sm, data, username) > 0) {
+ os_free(username);
+ /*
+ * Since re-auth username was recognized, skip AKA/Identity
+ * exchange.
+ */
+ return;
+ }
+
+ if ((data->eap_method == EAP_TYPE_AKA_PRIME &&
+ username[0] == EAP_AKA_PRIME_PSEUDONYM_PREFIX) ||
+ (data->eap_method == EAP_TYPE_AKA &&
+ username[0] == EAP_AKA_PSEUDONYM_PREFIX)) {
+ const char *permanent;
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Pseudonym username '%s'",
+ username);
+ permanent = eap_sim_db_get_permanent(
+ sm->eap_sim_db_priv, username);
+ if (permanent == NULL) {
+ os_free(username);
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown pseudonym "
+ "identity - request permanent identity");
+ /* Remain in IDENTITY state for another round */
+ return;
+ }
+ os_strlcpy(data->permanent, permanent,
+ sizeof(data->permanent));
+ /*
+ * Since pseudonym username was recognized, skip AKA/Identity
+ * exchange.
+ */
+ eap_aka_fullauth(sm, data);
+ }
+
+ os_free(username);
+}
+
+
static void * eap_aka_init(struct eap_sm *sm)
{
struct eap_aka_data *data;
@@ -103,8 +193,8 @@ static void * eap_aka_init(struct eap_sm *sm)
data->eap_method = EAP_TYPE_AKA;
data->state = IDENTITY;
- eap_aka_determine_identity(sm, data, 1, 0);
data->pending_id = -1;
+ eap_aka_check_identity(sm, data);
return data;
}
@@ -136,8 +226,8 @@ static void * eap_aka_prime_init(struct eap_sm *sm)
data->network_name_len = os_strlen(network_name);
data->state = IDENTITY;
- eap_aka_determine_identity(sm, data, 1, 0);
data->pending_id = -1;
+ eap_aka_check_identity(sm, data);
return data;
}
@@ -264,21 +354,8 @@ static struct wpabuf * eap_aka_build_identity(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Identity");
msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
EAP_AKA_SUBTYPE_IDENTITY);
- if (eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
- sm->identity_len)) {
- if (sm->identity_len > 0 &&
- (sm->identity[0] == EAP_AKA_REAUTH_ID_PREFIX ||
- sm->identity[0] == EAP_AKA_PRIME_REAUTH_ID_PREFIX)) {
- /* Reauth id may have expired - try fullauth */
- wpa_printf(MSG_DEBUG, " AT_FULLAUTH_ID_REQ");
- eap_sim_msg_add(msg, EAP_SIM_AT_FULLAUTH_ID_REQ, 0,
- NULL, 0);
- } else {
- wpa_printf(MSG_DEBUG, " AT_PERMANENT_ID_REQ");
- eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0,
- NULL, 0);
- }
- } else {
+ data->identity_round++;
+ if (data->identity_round == 1) {
/*
* RFC 4187, Chap. 4.1.4 recommends that identity from EAP is
* ignored and the AKA/Identity is used to request the
@@ -286,6 +363,18 @@ static struct wpabuf * eap_aka_build_identity(struct eap_sm *sm,
*/
wpa_printf(MSG_DEBUG, " AT_ANY_ID_REQ");
eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0);
+ } else if (data->identity_round > 3) {
+ /* Cannot use more than three rounds of Identity messages */
+ return NULL;
+ } else if (sm->identity && sm->identity_len > 0 &&
+ (sm->identity[0] == EAP_AKA_REAUTH_ID_PREFIX ||
+ sm->identity[0] == EAP_AKA_PRIME_REAUTH_ID_PREFIX)) {
+ /* Reauth id may have expired - try fullauth */
+ wpa_printf(MSG_DEBUG, " AT_FULLAUTH_ID_REQ");
+ eap_sim_msg_add(msg, EAP_SIM_AT_FULLAUTH_ID_REQ, 0, NULL, 0);
+ } else {
+ wpa_printf(MSG_DEBUG, " AT_PERMANENT_ID_REQ");
+ eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
}
buf = eap_sim_msg_finish(msg, NULL, NULL, 0);
if (eap_aka_add_id_msg(data, buf) < 0) {
@@ -622,93 +711,72 @@ static Boolean eap_aka_subtype_ok(struct eap_aka_data *data, u8 subtype)
static void eap_aka_determine_identity(struct eap_sm *sm,
- struct eap_aka_data *data,
- int before_identity, int after_reauth)
+ struct eap_aka_data *data)
{
- const u8 *identity;
- size_t identity_len;
- int res;
+ char *username;
- identity = NULL;
- identity_len = 0;
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity",
+ sm->identity, sm->identity_len);
- if (after_reauth && data->reauth) {
- identity = data->reauth->identity;
- identity_len = data->reauth->identity_len;
- } else if (sm->identity && sm->identity_len > 0 &&
- (sm->identity[0] == EAP_AKA_PERMANENT_PREFIX ||
- sm->identity[0] == EAP_AKA_PRIME_PERMANENT_PREFIX)) {
- identity = sm->identity;
- identity_len = sm->identity_len;
- } else {
- identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv,
- sm->identity,
- sm->identity_len,
- &identity_len);
- if (identity == NULL) {
- data->reauth = eap_sim_db_get_reauth_entry(
- sm->eap_sim_db_priv, sm->identity,
- sm->identity_len);
- if (data->reauth &&
- data->reauth->aka_prime !=
- (data->eap_method == EAP_TYPE_AKA_PRIME)) {
- wpa_printf(MSG_DEBUG, "EAP-AKA: Reauth data "
- "was for different AKA version");
- data->reauth = NULL;
- }
- if (data->reauth) {
- wpa_printf(MSG_DEBUG, "EAP-AKA: Using fast "
- "re-authentication");
- identity = data->reauth->identity;
- identity_len = data->reauth->identity_len;
- data->counter = data->reauth->counter;
- if (data->eap_method == EAP_TYPE_AKA_PRIME) {
- os_memcpy(data->k_encr,
- data->reauth->k_encr,
- EAP_SIM_K_ENCR_LEN);
- os_memcpy(data->k_aut,
- data->reauth->k_aut,
- EAP_AKA_PRIME_K_AUT_LEN);
- os_memcpy(data->k_re,
- data->reauth->k_re,
- EAP_AKA_PRIME_K_RE_LEN);
- } else {
- os_memcpy(data->mk, data->reauth->mk,
- EAP_SIM_MK_LEN);
- }
- }
- }
+ username = sim_get_username(sm->identity, sm->identity_len);
+ if (username == NULL) {
+ data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+ eap_aka_state(data, NOTIFICATION);
+ return;
+ }
+
+ if (eap_aka_check_identity_reauth(sm, data, username) > 0) {
+ os_free(username);
+ return;
}
- if (identity == NULL ||
- eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
- sm->identity_len) < 0) {
- if (before_identity) {
- wpa_printf(MSG_DEBUG, "EAP-AKA: Permanent user name "
- "not known - send AKA-Identity request");
- eap_aka_state(data, IDENTITY);
+ if ((data->eap_method == EAP_TYPE_AKA_PRIME &&
+ username[0] == EAP_AKA_PRIME_PSEUDONYM_PREFIX) ||
+ (data->eap_method == EAP_TYPE_AKA &&
+ username[0] == EAP_AKA_PSEUDONYM_PREFIX)) {
+ const char *permanent;
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Pseudonym username '%s'",
+ username);
+ permanent = eap_sim_db_get_permanent(
+ sm->eap_sim_db_priv, username);
+ os_free(username);
+ if (permanent == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown pseudonym "
+ "identity - request permanent identity");
+ /* Remain in IDENTITY state for another round */
return;
- } else {
- wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown whether the "
- "permanent user name is known; try to use "
- "it");
- /* eap_sim_db_get_aka_auth() will report failure, if
- * this identity is not known. */
}
+ os_strlcpy(data->permanent, permanent,
+ sizeof(data->permanent));
+ } else if ((data->eap_method == EAP_TYPE_AKA_PRIME &&
+ username[0] == EAP_AKA_PRIME_PERMANENT_PREFIX) ||
+ (data->eap_method == EAP_TYPE_AKA &&
+ username[0] == EAP_AKA_PERMANENT_PREFIX)) {
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Permanent username '%s'",
+ username);
+ os_strlcpy(data->permanent, username, sizeof(data->permanent));
+ os_free(username);
+ } else {
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized username '%s'",
+ username);
+ os_free(username);
+ data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+ eap_aka_state(data, NOTIFICATION);
+ return;
}
- wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity",
- identity, identity_len);
+ eap_aka_fullauth(sm, data);
+}
- if (!after_reauth && data->reauth) {
- eap_aka_state(data, REAUTH);
- return;
- }
- res = eap_sim_db_get_aka_auth(sm->eap_sim_db_priv, identity,
- identity_len, data->rand, data->autn,
- data->ik, data->ck, data->res,
- &data->res_len, sm);
+static void eap_aka_fullauth(struct eap_sm *sm, struct eap_aka_data *data)
+{
+ size_t identity_len;
+ int res;
+
+ res = eap_sim_db_get_aka_auth(sm->eap_sim_db_priv, data->permanent,
+ data->rand, data->autn, data->ik,
+ data->ck, data->res, &data->res_len, sm);
if (res == EAP_SIM_DB_PENDING) {
wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data "
"not yet available - pending request");
@@ -772,6 +840,8 @@ static void eap_aka_process_identity(struct eap_sm *sm,
struct wpabuf *respData,
struct eap_sim_attrs *attr)
{
+ u8 *new_identity;
+
wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Identity");
if (attr->mac || attr->iv || attr->encr_data) {
@@ -782,17 +852,30 @@ static void eap_aka_process_identity(struct eap_sm *sm,
return;
}
- if (attr->identity) {
- os_free(sm->identity);
- sm->identity = os_malloc(attr->identity_len);
- if (sm->identity) {
- os_memcpy(sm->identity, attr->identity,
- attr->identity_len);
- sm->identity_len = attr->identity_len;
- }
+ /*
+ * We always request identity with AKA/Identity, so the peer is
+ * required to have replied with one.
+ */
+ if (!attr->identity || attr->identity_len == 0) {
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Peer did not provide any "
+ "identity");
+ data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+ eap_aka_state(data, NOTIFICATION);
+ return;
}
- eap_aka_determine_identity(sm, data, 0, 0);
+ new_identity = os_malloc(attr->identity_len);
+ if (new_identity == NULL) {
+ data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+ eap_aka_state(data, NOTIFICATION);
+ return;
+ }
+ os_free(sm->identity);
+ sm->identity = new_identity;
+ os_memcpy(sm->identity, attr->identity, attr->identity_len);
+ sm->identity_len = attr->identity_len;
+
+ eap_aka_determine_identity(sm, data);
if (eap_get_id(respData) == data->pending_id) {
data->pending_id = -1;
eap_aka_add_id_msg(data, respData);
@@ -817,9 +900,6 @@ static void eap_aka_process_challenge(struct eap_sm *sm,
struct wpabuf *respData,
struct eap_sim_attrs *attr)
{
- const u8 *identity;
- size_t identity_len;
-
wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Challenge");
#ifdef EAP_SERVER_AKA_PRIME
@@ -892,16 +972,8 @@ static void eap_aka_process_challenge(struct eap_sm *sm,
} else
eap_aka_state(data, SUCCESS);
- identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, sm->identity,
- sm->identity_len, &identity_len);
- if (identity == NULL) {
- identity = sm->identity;
- identity_len = sm->identity_len;
- }
-
if (data->next_pseudonym) {
- eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity,
- identity_len,
+ eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, data->permanent,
data->next_pseudonym);
data->next_pseudonym = NULL;
}
@@ -909,16 +981,15 @@ static void eap_aka_process_challenge(struct eap_sm *sm,
if (data->eap_method == EAP_TYPE_AKA_PRIME) {
#ifdef EAP_SERVER_AKA_PRIME
eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv,
- identity,
- identity_len,
+ data->permanent,
data->next_reauth_id,
data->counter + 1,
data->k_encr, data->k_aut,
data->k_re);
#endif /* EAP_SERVER_AKA_PRIME */
} else {
- eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
- identity_len,
+ eap_sim_db_add_reauth(sm->eap_sim_db_priv,
+ data->permanent,
data->next_reauth_id,
data->counter + 1,
data->mk);
@@ -947,9 +1018,8 @@ static void eap_aka_process_sync_failure(struct eap_sm *sm,
* maintaining a local flag stating whether this AUTS has already been
* reported. */
if (!data->auts_reported &&
- eap_sim_db_resynchronize(sm->eap_sim_db_priv, sm->identity,
- sm->identity_len, attr->auts,
- data->rand)) {
+ eap_sim_db_resynchronize(sm->eap_sim_db_priv, data->permanent,
+ attr->auts, data->rand)) {
wpa_printf(MSG_WARNING, "EAP-AKA: Resynchronization failed");
data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
eap_aka_state(data, NOTIFICATION);
@@ -957,8 +1027,7 @@ static void eap_aka_process_sync_failure(struct eap_sm *sm,
}
data->auts_reported = 1;
- /* Try again after resynchronization */
- eap_aka_determine_identity(sm, data, 0, 0);
+ /* Remain in CHALLENGE state to re-try after resynchronization */
}
@@ -969,8 +1038,6 @@ static void eap_aka_process_reauth(struct eap_sm *sm,
{
struct eap_sim_attrs eattr;
u8 *decrypted = NULL;
- const u8 *identity, *id2;
- size_t identity_len, id2_len;
wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Reauthentication");
@@ -1013,7 +1080,7 @@ static void eap_aka_process_reauth(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response "
"included AT_COUNTER_TOO_SMALL - starting full "
"authentication");
- eap_aka_determine_identity(sm, data, 0, 1);
+ eap_aka_fullauth(sm, data);
return;
}
@@ -1024,35 +1091,19 @@ static void eap_aka_process_reauth(struct eap_sm *sm,
} else
eap_aka_state(data, SUCCESS);
- if (data->reauth) {
- identity = data->reauth->identity;
- identity_len = data->reauth->identity_len;
- } else {
- identity = sm->identity;
- identity_len = sm->identity_len;
- }
-
- id2 = eap_sim_db_get_permanent(sm->eap_sim_db_priv, identity,
- identity_len, &id2_len);
- if (id2) {
- identity = id2;
- identity_len = id2_len;
- }
-
if (data->next_reauth_id) {
if (data->eap_method == EAP_TYPE_AKA_PRIME) {
#ifdef EAP_SERVER_AKA_PRIME
eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv,
- identity,
- identity_len,
+ data->permanent,
data->next_reauth_id,
data->counter + 1,
data->k_encr, data->k_aut,
data->k_re);
#endif /* EAP_SERVER_AKA_PRIME */
} else {
- eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
- identity_len,
+ eap_sim_db_add_reauth(sm->eap_sim_db_priv,
+ data->permanent,
data->next_reauth_id,
data->counter + 1,
data->mk);
diff --git a/src/eap_server/eap_server_sim.c b/src/eap_server/eap_server_sim.c
index 6658d9c..f83c3cb 100644
--- a/src/eap_server/eap_server_sim.c
+++ b/src/eap_server/eap_server_sim.c
@@ -1,6 +1,6 @@
/*
* hostapd / EAP-SIM (RFC 4186)
- * Copyright (c) 2005-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -36,6 +36,8 @@ struct eap_sim_data {
struct eap_sim_reauth *reauth;
u16 notification;
int use_result_ind;
+ int start_round;
+ char permanent[20]; /* Permanent username */
};
@@ -105,26 +107,32 @@ static struct wpabuf * eap_sim_build_start(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Start");
msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
EAP_SIM_SUBTYPE_START);
- if (eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
- sm->identity_len)) {
- if (sm->identity_len > 0 &&
- sm->identity[0] == EAP_SIM_REAUTH_ID_PREFIX) {
- /* Reauth id may have expired - try fullauth */
- wpa_printf(MSG_DEBUG, " AT_FULLAUTH_ID_REQ");
- eap_sim_msg_add(msg, EAP_SIM_AT_FULLAUTH_ID_REQ, 0,
- NULL, 0);
- } else {
- wpa_printf(MSG_DEBUG, " AT_PERMANENT_ID_REQ");
- eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0,
- NULL, 0);
- }
- } else {
+ data->start_round++;
+ if (data->start_round == 1) {
/*
* RFC 4186, Chap. 4.2.4 recommends that identity from EAP is
* ignored and the SIM/Start is used to request the identity.
*/
wpa_printf(MSG_DEBUG, " AT_ANY_ID_REQ");
eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0);
+ } else if (data->start_round > 3) {
+ /* Cannot use more than three rounds of Start messages */
+ return NULL;
+ } else if (data->start_round == 0) {
+ /*
+ * This is a special case that is used to recover from
+ * AT_COUNTER_TOO_SMALL during re-authentication. Since we
+ * already know the identity of the peer, there is no need to
+ * request any identity in this case.
+ */
+ } else if (sm->identity && sm->identity_len > 0 &&
+ sm->identity[0] == EAP_SIM_REAUTH_ID_PREFIX) {
+ /* Reauth id may have expired - try fullauth */
+ wpa_printf(MSG_DEBUG, " AT_FULLAUTH_ID_REQ");
+ eap_sim_msg_add(msg, EAP_SIM_AT_FULLAUTH_ID_REQ, 0, NULL, 0);
+ } else {
+ wpa_printf(MSG_DEBUG, " AT_PERMANENT_ID_REQ");
+ eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
}
wpa_printf(MSG_DEBUG, " AT_VERSION_LIST");
ver[0] = 0;
@@ -337,18 +345,22 @@ static struct wpabuf * eap_sim_buildReq(struct eap_sm *sm, void *priv, u8 id)
static Boolean eap_sim_check(struct eap_sm *sm, void *priv,
struct wpabuf *respData)
{
- struct eap_sim_data *data = priv;
const u8 *pos;
size_t len;
- u8 subtype;
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, respData, &len);
if (pos == NULL || len < 3) {
wpa_printf(MSG_INFO, "EAP-SIM: Invalid frame");
return TRUE;
}
- subtype = *pos;
+ return FALSE;
+}
+
+
+static Boolean eap_sim_unexpected_subtype(struct eap_sim_data *data,
+ u8 subtype)
+{
if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR)
return FALSE;
@@ -402,85 +414,113 @@ static void eap_sim_process_start(struct eap_sm *sm,
struct wpabuf *respData,
struct eap_sim_attrs *attr)
{
- const u8 *identity;
size_t identity_len;
u8 ver_list[2];
+ u8 *new_identity;
+ char *username;
wpa_printf(MSG_DEBUG, "EAP-SIM: Receive start response");
- if (attr->identity) {
- os_free(sm->identity);
- sm->identity = os_malloc(attr->identity_len);
- if (sm->identity) {
- os_memcpy(sm->identity, attr->identity,
- attr->identity_len);
- sm->identity_len = attr->identity_len;
- }
+ if (data->start_round == 0) {
+ /*
+ * Special case for AT_COUNTER_TOO_SMALL recovery - no identity
+ * was requested since we already know it.
+ */
+ goto skip_id_update;
}
- identity = NULL;
- identity_len = 0;
-
- if (sm->identity && sm->identity_len > 0 &&
- sm->identity[0] == EAP_SIM_PERMANENT_PREFIX) {
- identity = sm->identity;
- identity_len = sm->identity_len;
- } else {
- identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv,
- sm->identity,
- sm->identity_len,
- &identity_len);
- if (identity == NULL) {
- data->reauth = eap_sim_db_get_reauth_entry(
- sm->eap_sim_db_priv, sm->identity,
- sm->identity_len);
- if (data->reauth) {
- wpa_printf(MSG_DEBUG, "EAP-SIM: Using fast "
- "re-authentication");
- identity = data->reauth->identity;
- identity_len = data->reauth->identity_len;
- data->counter = data->reauth->counter;
- os_memcpy(data->mk, data->reauth->mk,
- EAP_SIM_MK_LEN);
- }
- }
+ /*
+ * We always request identity in SIM/Start, so the peer is required to
+ * have replied with one.
+ */
+ if (!attr->identity || attr->identity_len == 0) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Peer did not provide any "
+ "identity");
+ goto failed;
}
- if (identity == NULL) {
- wpa_printf(MSG_DEBUG, "EAP-SIM: Could not get proper permanent"
- " user name");
- eap_sim_state(data, FAILURE);
- return;
- }
+ new_identity = os_malloc(attr->identity_len);
+ if (new_identity == NULL)
+ goto failed;
+ os_free(sm->identity);
+ sm->identity = new_identity;
+ os_memcpy(sm->identity, attr->identity, attr->identity_len);
+ sm->identity_len = attr->identity_len;
wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity",
- identity, identity_len);
-
- if (data->reauth) {
+ sm->identity, sm->identity_len);
+ username = sim_get_username(sm->identity, sm->identity_len);
+ if (username == NULL)
+ goto failed;
+
+ if (username[0] == EAP_SIM_REAUTH_ID_PREFIX) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Reauth username '%s'",
+ username);
+ data->reauth = eap_sim_db_get_reauth_entry(
+ sm->eap_sim_db_priv, username);
+ os_free(username);
+ if (data->reauth == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown reauth "
+ "identity - request full auth identity");
+ /* Remain in START state for another round */
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Using fast re-authentication");
+ os_strlcpy(data->permanent, data->reauth->permanent,
+ sizeof(data->permanent));
+ data->counter = data->reauth->counter;
+ os_memcpy(data->mk, data->reauth->mk, EAP_SIM_MK_LEN);
eap_sim_state(data, REAUTH);
return;
}
+ if (username[0] == EAP_SIM_PSEUDONYM_PREFIX) {
+ const char *permanent;
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Pseudonym username '%s'",
+ username);
+ permanent = eap_sim_db_get_permanent(
+ sm->eap_sim_db_priv, username);
+ os_free(username);
+ if (permanent == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown pseudonym "
+ "identity - request permanent identity");
+ /* Remain in START state for another round */
+ return;
+ }
+ os_strlcpy(data->permanent, permanent,
+ sizeof(data->permanent));
+ } else if (username[0] == EAP_SIM_PERMANENT_PREFIX) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Permanent username '%s'",
+ username);
+ os_strlcpy(data->permanent, username, sizeof(data->permanent));
+ os_free(username);
+ } else {
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized username '%s'",
+ username);
+ os_free(username);
+ goto failed;
+ }
+
+skip_id_update:
+ /* Full authentication */
+
if (attr->nonce_mt == NULL || attr->selected_version < 0) {
wpa_printf(MSG_DEBUG, "EAP-SIM: Start/Response missing "
"required attributes");
- eap_sim_state(data, FAILURE);
- return;
+ goto failed;
}
if (!eap_sim_supported_ver(data, attr->selected_version)) {
wpa_printf(MSG_DEBUG, "EAP-SIM: Peer selected unsupported "
"version %d", attr->selected_version);
- eap_sim_state(data, FAILURE);
- return;
+ goto failed;
}
data->counter = 0; /* reset re-auth counter since this is full auth */
data->reauth = NULL;
data->num_chal = eap_sim_db_get_gsm_triplets(
- sm->eap_sim_db_priv, identity, identity_len,
- EAP_SIM_MAX_CHAL,
+ sm->eap_sim_db_priv, data->permanent, EAP_SIM_MAX_CHAL,
(u8 *) data->rand, (u8 *) data->kc, (u8 *) data->sres, sm);
if (data->num_chal == EAP_SIM_DB_PENDING) {
wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication triplets "
@@ -491,8 +531,7 @@ static void eap_sim_process_start(struct eap_sm *sm,
if (data->num_chal < 2) {
wpa_printf(MSG_INFO, "EAP-SIM: Failed to get GSM "
"authentication triplets for the peer");
- eap_sim_state(data, FAILURE);
- return;
+ goto failed;
}
identity_len = sm->identity_len;
@@ -513,6 +552,11 @@ static void eap_sim_process_start(struct eap_sm *sm,
data->emsk);
eap_sim_state(data, CHALLENGE);
+ return;
+
+failed:
+ data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+ eap_sim_state(data, NOTIFICATION);
}
@@ -521,16 +565,14 @@ static void eap_sim_process_challenge(struct eap_sm *sm,
struct wpabuf *respData,
struct eap_sim_attrs *attr)
{
- const u8 *identity;
- size_t identity_len;
-
if (attr->mac == NULL ||
eap_sim_verify_mac(data->k_aut, respData, attr->mac,
(u8 *) data->sres,
data->num_chal * EAP_SIM_SRES_LEN)) {
wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
"did not include valid AT_MAC");
- eap_sim_state(data, FAILURE);
+ data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+ eap_sim_state(data, NOTIFICATION);
return;
}
@@ -543,22 +585,13 @@ static void eap_sim_process_challenge(struct eap_sm *sm,
} else
eap_sim_state(data, SUCCESS);
- identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, sm->identity,
- sm->identity_len, &identity_len);
- if (identity == NULL) {
- identity = sm->identity;
- identity_len = sm->identity_len;
- }
-
if (data->next_pseudonym) {
- eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity,
- identity_len,
+ eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, data->permanent,
data->next_pseudonym);
data->next_pseudonym = NULL;
}
if (data->next_reauth_id) {
- eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
- identity_len,
+ eap_sim_db_add_reauth(sm->eap_sim_db_priv, data->permanent,
data->next_reauth_id, data->counter + 1,
data->mk);
data->next_reauth_id = NULL;
@@ -573,8 +606,6 @@ static void eap_sim_process_reauth(struct eap_sm *sm,
{
struct eap_sim_attrs eattr;
u8 *decrypted = NULL;
- const u8 *identity, *id2;
- size_t identity_len, id2_len;
if (attr->mac == NULL ||
eap_sim_verify_mac(data->k_aut, respData, attr->mac, data->nonce_s,
@@ -610,6 +641,16 @@ static void eap_sim_process_reauth(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "EAP-SIM: Re-authentication response includes "
"the correct AT_MAC");
+
+ if (eattr.counter_too_small) {
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response "
+ "included AT_COUNTER_TOO_SMALL - starting full "
+ "authentication");
+ data->start_round = -1;
+ eap_sim_state(data, START);
+ return;
+ }
+
if (sm->eap_sim_aka_result_ind && attr->result_ind) {
data->use_result_ind = 1;
data->notification = EAP_SIM_SUCCESS;
@@ -617,24 +658,9 @@ static void eap_sim_process_reauth(struct eap_sm *sm,
} else
eap_sim_state(data, SUCCESS);
- if (data->reauth) {
- identity = data->reauth->identity;
- identity_len = data->reauth->identity_len;
- } else {
- identity = sm->identity;
- identity_len = sm->identity_len;
- }
-
- id2 = eap_sim_db_get_permanent(sm->eap_sim_db_priv, identity,
- identity_len, &id2_len);
- if (id2) {
- identity = id2;
- identity_len = id2_len;
- }
-
if (data->next_reauth_id) {
- eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
- identity_len, data->next_reauth_id,
+ eap_sim_db_add_reauth(sm->eap_sim_db_priv, data->permanent,
+ data->next_reauth_id,
data->counter + 1, data->mk);
data->next_reauth_id = NULL;
} else {
@@ -645,7 +671,8 @@ static void eap_sim_process_reauth(struct eap_sm *sm,
return;
fail:
- eap_sim_state(data, FAILURE);
+ data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+ eap_sim_state(data, NOTIFICATION);
eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
data->reauth = NULL;
os_free(decrypted);
@@ -696,8 +723,24 @@ static void eap_sim_process(struct eap_sm *sm, void *priv,
subtype = *pos;
pos += 3;
+ if (eap_sim_unexpected_subtype(data, subtype)) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized or unexpected "
+ "EAP-SIM Subtype in EAP Response");
+ data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+ eap_sim_state(data, NOTIFICATION);
+ return;
+ }
+
if (eap_sim_parse_attr(pos, end, &attr, 0, 0)) {
wpa_printf(MSG_DEBUG, "EAP-SIM: Failed to parse attributes");
+ if (subtype != EAP_SIM_SUBTYPE_CLIENT_ERROR &&
+ (data->state == START || data->state == CHALLENGE ||
+ data->state == REAUTH)) {
+ data->notification =
+ EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+ eap_sim_state(data, NOTIFICATION);
+ return;
+ }
eap_sim_state(data, FAILURE);
return;
}
diff --git a/src/eap_server/eap_sim_db.c b/src/eap_server/eap_sim_db.c
index 68fb1f0..257013e 100644
--- a/src/eap_server/eap_sim_db.c
+++ b/src/eap_server/eap_sim_db.c
@@ -17,6 +17,9 @@
#include "includes.h"
#include <sys/un.h>
+#ifdef CONFIG_SQLITE
+#include <sqlite3.h>
+#endif /* CONFIG_SQLITE */
#include "common.h"
#include "crypto/random.h"
@@ -26,15 +29,13 @@
struct eap_sim_pseudonym {
struct eap_sim_pseudonym *next;
- u8 *identity;
- size_t identity_len;
- char *pseudonym;
+ char *permanent; /* permanent username */
+ char *pseudonym; /* pseudonym username */
};
struct eap_sim_db_pending {
struct eap_sim_db_pending *next;
- u8 imsi[20];
- size_t imsi_len;
+ char imsi[20];
enum { PENDING, SUCCESS, FAILURE } state;
void *cb_session_ctx;
struct os_time timestamp;
@@ -66,19 +67,316 @@ struct eap_sim_db_data {
struct eap_sim_pseudonym *pseudonyms;
struct eap_sim_reauth *reauths;
struct eap_sim_db_pending *pending;
+#ifdef CONFIG_SQLITE
+ sqlite3 *sqlite_db;
+ char db_tmp_identity[100];
+ char db_tmp_pseudonym_str[100];
+ struct eap_sim_pseudonym db_tmp_pseudonym;
+ struct eap_sim_reauth db_tmp_reauth;
+#endif /* CONFIG_SQLITE */
};
+#ifdef CONFIG_SQLITE
+
+static int db_table_exists(sqlite3 *db, const char *name)
+{
+ char cmd[128];
+ os_snprintf(cmd, sizeof(cmd), "SELECT 1 FROM %s;", name);
+ return sqlite3_exec(db, cmd, NULL, NULL, NULL) == SQLITE_OK;
+}
+
+
+static int db_table_create_pseudonym(sqlite3 *db)
+{
+ char *err = NULL;
+ const char *sql =
+ "CREATE TABLE pseudonyms("
+ " permanent CHAR(21) PRIMARY KEY,"
+ " pseudonym CHAR(21) NOT NULL"
+ ");";
+
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Adding database table for "
+ "pseudonym information");
+ if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
+ wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err);
+ sqlite3_free(err);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int db_table_create_reauth(sqlite3 *db)
+{
+ char *err = NULL;
+ const char *sql =
+ "CREATE TABLE reauth("
+ " permanent CHAR(21) PRIMARY KEY,"
+ " reauth_id CHAR(21) NOT NULL,"
+ " counter INTEGER,"
+ " mk CHAR(40),"
+ " k_encr CHAR(32),"
+ " k_aut CHAR(64),"
+ " k_re CHAR(64)"
+ ");";
+
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Adding database table for "
+ "reauth information");
+ if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
+ wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err);
+ sqlite3_free(err);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static sqlite3 * db_open(const char *db_file)
+{
+ sqlite3 *db;
+
+ if (sqlite3_open(db_file, &db)) {
+ wpa_printf(MSG_ERROR, "EAP-SIM DB: Failed to open database "
+ "%s: %s", db_file, sqlite3_errmsg(db));
+ sqlite3_close(db);
+ return NULL;
+ }
+
+ if (!db_table_exists(db, "pseudonyms") &&
+ db_table_create_pseudonym(db) < 0) {
+ sqlite3_close(db);
+ return NULL;
+ }
+
+ if (!db_table_exists(db, "reauth") &&
+ db_table_create_reauth(db) < 0) {
+ sqlite3_close(db);
+ return NULL;
+ }
+
+ return db;
+}
+
+
+static int valid_db_string(const char *str)
+{
+ const char *pos = str;
+ while (*pos) {
+ if ((*pos < '0' || *pos > '9') &&
+ (*pos < 'a' || *pos > 'f'))
+ return 0;
+ pos++;
+ }
+ return 1;
+}
+
+
+static int db_add_pseudonym(struct eap_sim_db_data *data,
+ const char *permanent, char *pseudonym)
+{
+ char cmd[128];
+ char *err = NULL;
+
+ if (!valid_db_string(permanent) || !valid_db_string(pseudonym)) {
+ os_free(pseudonym);
+ return -1;
+ }
+
+ os_snprintf(cmd, sizeof(cmd), "INSERT OR REPLACE INTO pseudonyms "
+ "(permanent, pseudonym) VALUES ('%s', '%s');",
+ permanent, pseudonym);
+ os_free(pseudonym);
+ if (sqlite3_exec(data->sqlite_db, cmd, NULL, NULL, &err) != SQLITE_OK)
+ {
+ wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err);
+ sqlite3_free(err);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int get_pseudonym_cb(void *ctx, int argc, char *argv[], char *col[])
+{
+ struct eap_sim_db_data *data = ctx;
+ int i;
+
+ for (i = 0; i < argc; i++) {
+ if (os_strcmp(col[i], "permanent") == 0 && argv[i]) {
+ os_strlcpy(data->db_tmp_identity, argv[i],
+ sizeof(data->db_tmp_identity));
+ }
+ }
+
+ return 0;
+}
+
+
+static char *
+db_get_pseudonym(struct eap_sim_db_data *data, const char *pseudonym)
+{
+ char cmd[128];
+
+ if (!valid_db_string(pseudonym))
+ return NULL;
+ os_memset(&data->db_tmp_identity, 0, sizeof(data->db_tmp_identity));
+ os_snprintf(cmd, sizeof(cmd),
+ "SELECT permanent FROM pseudonyms WHERE pseudonym='%s';",
+ pseudonym);
+ if (sqlite3_exec(data->sqlite_db, cmd, get_pseudonym_cb, data, NULL) !=
+ SQLITE_OK)
+ return NULL;
+ if (data->db_tmp_identity[0] == '\0')
+ return NULL;
+ return data->db_tmp_identity;
+}
+
+
+static int db_add_reauth(struct eap_sim_db_data *data, const char *permanent,
+ char *reauth_id, u16 counter, const u8 *mk,
+ const u8 *k_encr, const u8 *k_aut, const u8 *k_re)
+{
+ char cmd[2000], *pos, *end;
+ char *err = NULL;
+
+ if (!valid_db_string(permanent) || !valid_db_string(reauth_id)) {
+ os_free(reauth_id);
+ return -1;
+ }
+
+ pos = cmd;
+ end = pos + sizeof(cmd);
+ pos += os_snprintf(pos, end - pos, "INSERT OR REPLACE INTO reauth "
+ "(permanent, reauth_id, counter%s%s%s%s) "
+ "VALUES ('%s', '%s', %u",
+ mk ? ", mk" : "",
+ k_encr ? ", k_encr" : "",
+ k_aut ? ", k_aut" : "",
+ k_re ? ", k_re" : "",
+ permanent, reauth_id, counter);
+ os_free(reauth_id);
+
+ if (mk) {
+ pos += os_snprintf(pos, end - pos, ", '");
+ pos += wpa_snprintf_hex(pos, end - pos, mk, EAP_SIM_MK_LEN);
+ pos += os_snprintf(pos, end - pos, "'");
+ }
+
+ if (k_encr) {
+ pos += os_snprintf(pos, end - pos, ", '");
+ pos += wpa_snprintf_hex(pos, end - pos, k_encr,
+ EAP_SIM_K_ENCR_LEN);
+ pos += os_snprintf(pos, end - pos, "'");
+ }
+
+ if (k_aut) {
+ pos += os_snprintf(pos, end - pos, ", '");
+ pos += wpa_snprintf_hex(pos, end - pos, k_aut,
+ EAP_AKA_PRIME_K_AUT_LEN);
+ pos += os_snprintf(pos, end - pos, "'");
+ }
+
+ if (k_re) {
+ pos += os_snprintf(pos, end - pos, ", '");
+ pos += wpa_snprintf_hex(pos, end - pos, k_re,
+ EAP_AKA_PRIME_K_RE_LEN);
+ pos += os_snprintf(pos, end - pos, "'");
+ }
+
+ os_snprintf(pos, end - pos, ");");
+
+ if (sqlite3_exec(data->sqlite_db, cmd, NULL, NULL, &err) != SQLITE_OK)
+ {
+ wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err);
+ sqlite3_free(err);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int get_reauth_cb(void *ctx, int argc, char *argv[], char *col[])
+{
+ struct eap_sim_db_data *data = ctx;
+ int i;
+ struct eap_sim_reauth *reauth = &data->db_tmp_reauth;
+
+ for (i = 0; i < argc; i++) {
+ if (os_strcmp(col[i], "permanent") == 0 && argv[i]) {
+ os_strlcpy(data->db_tmp_identity, argv[i],
+ sizeof(data->db_tmp_identity));
+ reauth->permanent = data->db_tmp_identity;
+ } else if (os_strcmp(col[i], "counter") == 0 && argv[i]) {
+ reauth->counter = atoi(argv[i]);
+ } else if (os_strcmp(col[i], "mk") == 0 && argv[i]) {
+ hexstr2bin(argv[i], reauth->mk, sizeof(reauth->mk));
+ } else if (os_strcmp(col[i], "k_encr") == 0 && argv[i]) {
+ hexstr2bin(argv[i], reauth->k_encr,
+ sizeof(reauth->k_encr));
+ } else if (os_strcmp(col[i], "k_aut") == 0 && argv[i]) {
+ hexstr2bin(argv[i], reauth->k_aut,
+ sizeof(reauth->k_aut));
+ } else if (os_strcmp(col[i], "k_re") == 0 && argv[i]) {
+ hexstr2bin(argv[i], reauth->k_re,
+ sizeof(reauth->k_re));
+ }
+ }
+
+ return 0;
+}
+
+
+static struct eap_sim_reauth *
+db_get_reauth(struct eap_sim_db_data *data, const char *reauth_id)
+{
+ char cmd[256];
+
+ if (!valid_db_string(reauth_id))
+ return NULL;
+ os_memset(&data->db_tmp_reauth, 0, sizeof(data->db_tmp_reauth));
+ os_strlcpy(data->db_tmp_pseudonym_str, reauth_id,
+ sizeof(data->db_tmp_pseudonym_str));
+ data->db_tmp_reauth.reauth_id = data->db_tmp_pseudonym_str;
+ os_snprintf(cmd, sizeof(cmd),
+ "SELECT * FROM reauth WHERE reauth_id='%s';", reauth_id);
+ if (sqlite3_exec(data->sqlite_db, cmd, get_reauth_cb, data, NULL) !=
+ SQLITE_OK)
+ return NULL;
+ if (data->db_tmp_reauth.permanent == NULL)
+ return NULL;
+ return &data->db_tmp_reauth;
+}
+
+
+static void db_remove_reauth(struct eap_sim_db_data *data,
+ struct eap_sim_reauth *reauth)
+{
+ char cmd[256];
+
+ if (!valid_db_string(reauth->permanent))
+ return;
+ os_snprintf(cmd, sizeof(cmd),
+ "DELETE FROM reauth WHERE permanent='%s';",
+ reauth->permanent);
+ sqlite3_exec(data->sqlite_db, cmd, NULL, NULL, NULL);
+}
+
+#endif /* CONFIG_SQLITE */
+
+
static struct eap_sim_db_pending *
-eap_sim_db_get_pending(struct eap_sim_db_data *data, const u8 *imsi,
- size_t imsi_len, int aka)
+eap_sim_db_get_pending(struct eap_sim_db_data *data, const char *imsi, int aka)
{
struct eap_sim_db_pending *entry, *prev = NULL;
entry = data->pending;
while (entry) {
- if (entry->aka == aka && entry->imsi_len == imsi_len &&
- os_memcmp(entry->imsi, imsi, imsi_len) == 0) {
+ if (entry->aka == aka && os_strcmp(entry->imsi, imsi) == 0) {
if (prev)
prev->next = entry->next;
else
@@ -113,7 +411,7 @@ static void eap_sim_db_sim_resp_auth(struct eap_sim_db_data *data,
* (IMSI = ASCII string, Kc/SRES/RAND = hex string)
*/
- entry = eap_sim_db_get_pending(data, (u8 *) imsi, os_strlen(imsi), 0);
+ entry = eap_sim_db_get_pending(data, imsi, 0);
if (entry == NULL) {
wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the "
"received message found");
@@ -191,7 +489,7 @@ static void eap_sim_db_aka_resp_auth(struct eap_sim_db_data *data,
* (IMSI = ASCII string, RAND/AUTN/IK/CK/RES = hex string)
*/
- entry = eap_sim_db_get_pending(data, (u8 *) imsi, os_strlen(imsi), 1);
+ entry = eap_sim_db_get_pending(data, imsi, 1);
if (entry == NULL) {
wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the "
"received message found");
@@ -390,11 +688,13 @@ static void eap_sim_db_close_socket(struct eap_sim_db_data *data)
* @ctx: Context pointer for get_complete_cb
* Returns: Pointer to a private data structure or %NULL on failure
*/
-void * eap_sim_db_init(const char *config,
- void (*get_complete_cb)(void *ctx, void *session_ctx),
- void *ctx)
+struct eap_sim_db_data *
+eap_sim_db_init(const char *config,
+ void (*get_complete_cb)(void *ctx, void *session_ctx),
+ void *ctx)
{
struct eap_sim_db_data *data;
+ char *pos;
data = os_zalloc(sizeof(*data));
if (data == NULL)
@@ -406,6 +706,16 @@ void * eap_sim_db_init(const char *config,
data->fname = os_strdup(config);
if (data->fname == NULL)
goto fail;
+ pos = os_strstr(data->fname, " db=");
+ if (pos) {
+ *pos = '\0';
+#ifdef CONFIG_SQLITE
+ pos += 4;
+ data->sqlite_db = db_open(pos);
+ if (data->sqlite_db == NULL)
+ goto fail;
+#endif /* CONFIG_SQLITE */
+ }
if (os_strncmp(data->fname, "unix:", 5) == 0) {
if (eap_sim_db_open_socket(data)) {
@@ -427,7 +737,7 @@ fail:
static void eap_sim_db_free_pseudonym(struct eap_sim_pseudonym *p)
{
- os_free(p->identity);
+ os_free(p->permanent);
os_free(p->pseudonym);
os_free(p);
}
@@ -435,7 +745,7 @@ static void eap_sim_db_free_pseudonym(struct eap_sim_pseudonym *p)
static void eap_sim_db_free_reauth(struct eap_sim_reauth *r)
{
- os_free(r->identity);
+ os_free(r->permanent);
os_free(r->reauth_id);
os_free(r);
}
@@ -452,6 +762,13 @@ void eap_sim_db_deinit(void *priv)
struct eap_sim_reauth *r, *prevr;
struct eap_sim_db_pending *pending, *prev_pending;
+#ifdef CONFIG_SQLITE
+ if (data->sqlite_db) {
+ sqlite3_close(data->sqlite_db);
+ data->sqlite_db = NULL;
+ }
+#endif /* CONFIG_SQLITE */
+
eap_sim_db_close_socket(data);
os_free(data->fname);
@@ -518,9 +835,8 @@ static void eap_sim_db_expire_pending(struct eap_sim_db_data *data)
/**
* eap_sim_db_get_gsm_triplets - Get GSM triplets
- * @priv: Private data pointer from eap_sim_db_init()
- * @identity: User name identity
- * @identity_len: Length of identity in bytes
+ * @data: Private data pointer from eap_sim_db_init()
+ * @username: Permanent username (prefix | IMSI)
* @max_chal: Maximum number of triplets
* @_rand: Buffer for RAND values
* @kc: Buffer for Kc values
@@ -532,9 +848,6 @@ static void eap_sim_db_expire_pending(struct eap_sim_db_data *data)
* callback function registered with eap_sim_db_init() will be called once the
* results become available.
*
- * In most cases, the user name is '1' | IMSI, i.e., 1 followed by the IMSI in
- * ASCII format.
- *
* When using an external server for GSM triplets, this function can always
* start a request and return EAP_SIM_DB_PENDING immediately if authentication
* triplets are not available. Once the triplets are received, callback
@@ -543,39 +856,28 @@ static void eap_sim_db_expire_pending(struct eap_sim_db_data *data)
* function will then be called again and the newly received triplets will then
* be given to the caller.
*/
-int eap_sim_db_get_gsm_triplets(void *priv, const u8 *identity,
- size_t identity_len, int max_chal,
+int eap_sim_db_get_gsm_triplets(struct eap_sim_db_data *data,
+ const char *username, int max_chal,
u8 *_rand, u8 *kc, u8 *sres,
void *cb_session_ctx)
{
- struct eap_sim_db_data *data = priv;
struct eap_sim_db_pending *entry;
int len, ret;
- size_t i;
char msg[40];
+ const char *imsi;
+ size_t imsi_len;
- if (identity_len < 2 || identity[0] != EAP_SIM_PERMANENT_PREFIX) {
- wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
- identity, identity_len);
- return EAP_SIM_DB_FAILURE;
- }
- identity++;
- identity_len--;
- for (i = 0; i < identity_len; i++) {
- if (identity[i] == '@') {
- identity_len = i;
- break;
- }
- }
- if (identity_len + 1 > sizeof(entry->imsi)) {
- wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
- identity, identity_len);
+ if (username == NULL || username[0] != EAP_SIM_PERMANENT_PREFIX ||
+ username[1] == '\0' || os_strlen(username) > sizeof(entry->imsi)) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: unexpected username '%s'",
+ username);
return EAP_SIM_DB_FAILURE;
}
- wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Get GSM triplets for IMSI",
- identity, identity_len);
+ imsi = username + 1;
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get GSM triplets for IMSI '%s'",
+ imsi);
- entry = eap_sim_db_get_pending(data, identity, identity_len, 0);
+ entry = eap_sim_db_get_pending(data, imsi, 0);
if (entry) {
int num_chal;
if (entry->state == FAILURE) {
@@ -610,18 +912,19 @@ int eap_sim_db_get_gsm_triplets(void *priv, const u8 *identity,
return EAP_SIM_DB_FAILURE;
}
+ imsi_len = os_strlen(imsi);
len = os_snprintf(msg, sizeof(msg), "SIM-REQ-AUTH ");
- if (len < 0 || len + identity_len >= sizeof(msg))
+ if (len < 0 || len + imsi_len >= sizeof(msg))
return EAP_SIM_DB_FAILURE;
- os_memcpy(msg + len, identity, identity_len);
- len += identity_len;
+ os_memcpy(msg + len, imsi, imsi_len);
+ len += imsi_len;
ret = os_snprintf(msg + len, sizeof(msg) - len, " %d", max_chal);
if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
return EAP_SIM_DB_FAILURE;
len += ret;
- wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: requesting SIM authentication "
- "data for IMSI", identity, identity_len);
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: requesting SIM authentication "
+ "data for IMSI '%s'", imsi);
if (eap_sim_db_send(data, msg, len) < 0)
return EAP_SIM_DB_FAILURE;
@@ -630,8 +933,7 @@ int eap_sim_db_get_gsm_triplets(void *priv, const u8 *identity,
return EAP_SIM_DB_FAILURE;
os_get_time(&entry->timestamp);
- os_memcpy(entry->imsi, identity, identity_len);
- entry->imsi_len = identity_len;
+ os_strlcpy(entry->imsi, imsi, sizeof(entry->imsi));
entry->cb_session_ctx = cb_session_ctx;
entry->state = PENDING;
eap_sim_db_add_pending(data, entry);
@@ -641,196 +943,6 @@ int eap_sim_db_get_gsm_triplets(void *priv, const u8 *identity,
}
-static struct eap_sim_pseudonym *
-eap_sim_db_get_pseudonym(struct eap_sim_db_data *data, const u8 *identity,
- size_t identity_len)
-{
- char *pseudonym;
- size_t len;
- struct eap_sim_pseudonym *p;
-
- if (identity_len == 0 ||
- (identity[0] != EAP_SIM_PSEUDONYM_PREFIX &&
- identity[0] != EAP_AKA_PSEUDONYM_PREFIX &&
- identity[0] != EAP_AKA_PRIME_PSEUDONYM_PREFIX))
- return NULL;
-
- /* Remove possible realm from identity */
- len = 0;
- while (len < identity_len) {
- if (identity[len] == '@')
- break;
- len++;
- }
-
- pseudonym = os_malloc(len + 1);
- if (pseudonym == NULL)
- return NULL;
- os_memcpy(pseudonym, identity, len);
- pseudonym[len] = '\0';
-
- p = data->pseudonyms;
- while (p) {
- if (os_strcmp(p->pseudonym, pseudonym) == 0)
- break;
- p = p->next;
- }
-
- os_free(pseudonym);
-
- return p;
-}
-
-
-static struct eap_sim_pseudonym *
-eap_sim_db_get_pseudonym_id(struct eap_sim_db_data *data, const u8 *identity,
- size_t identity_len)
-{
- struct eap_sim_pseudonym *p;
-
- if (identity_len == 0 ||
- (identity[0] != EAP_SIM_PERMANENT_PREFIX &&
- identity[0] != EAP_AKA_PERMANENT_PREFIX &&
- identity[0] != EAP_AKA_PRIME_PERMANENT_PREFIX))
- return NULL;
-
- p = data->pseudonyms;
- while (p) {
- if (identity_len == p->identity_len &&
- os_memcmp(p->identity, identity, identity_len) == 0)
- break;
- p = p->next;
- }
-
- return p;
-}
-
-
-static struct eap_sim_reauth *
-eap_sim_db_get_reauth(struct eap_sim_db_data *data, const u8 *identity,
- size_t identity_len)
-{
- char *reauth_id;
- size_t len;
- struct eap_sim_reauth *r;
-
- if (identity_len == 0 ||
- (identity[0] != EAP_SIM_REAUTH_ID_PREFIX &&
- identity[0] != EAP_AKA_REAUTH_ID_PREFIX &&
- identity[0] != EAP_AKA_PRIME_REAUTH_ID_PREFIX))
- return NULL;
-
- /* Remove possible realm from identity */
- len = 0;
- while (len < identity_len) {
- if (identity[len] == '@')
- break;
- len++;
- }
-
- reauth_id = os_malloc(len + 1);
- if (reauth_id == NULL)
- return NULL;
- os_memcpy(reauth_id, identity, len);
- reauth_id[len] = '\0';
-
- r = data->reauths;
- while (r) {
- if (os_strcmp(r->reauth_id, reauth_id) == 0)
- break;
- r = r->next;
- }
-
- os_free(reauth_id);
-
- return r;
-}
-
-
-static struct eap_sim_reauth *
-eap_sim_db_get_reauth_id(struct eap_sim_db_data *data, const u8 *identity,
- size_t identity_len)
-{
- struct eap_sim_pseudonym *p;
- struct eap_sim_reauth *r;
-
- if (identity_len == 0)
- return NULL;
-
- p = eap_sim_db_get_pseudonym(data, identity, identity_len);
- if (p == NULL)
- p = eap_sim_db_get_pseudonym_id(data, identity, identity_len);
- if (p) {
- identity = p->identity;
- identity_len = p->identity_len;
- }
-
- r = data->reauths;
- while (r) {
- if (identity_len == r->identity_len &&
- os_memcmp(r->identity, identity, identity_len) == 0)
- break;
- r = r->next;
- }
-
- return r;
-}
-
-
-/**
- * eap_sim_db_identity_known - Verify whether the given identity is known
- * @priv: Private data pointer from eap_sim_db_init()
- * @identity: User name identity
- * @identity_len: Length of identity in bytes
- * Returns: 0 if the user is found or -1 on failure
- *
- * In most cases, the user name is ['0','1','6'] | IMSI, i.e., 1 followed by
- * the IMSI in ASCII format for EAP-SIM, ['2','3','7'] | pseudonym, or
- * ['4','5','7'] | reauth_id.
- */
-int eap_sim_db_identity_known(void *priv, const u8 *identity,
- size_t identity_len)
-{
- struct eap_sim_db_data *data = priv;
-
- if (identity == NULL || identity_len < 2)
- return -1;
-
- if (identity[0] == EAP_SIM_PSEUDONYM_PREFIX ||
- identity[0] == EAP_AKA_PSEUDONYM_PREFIX ||
- identity[0] == EAP_AKA_PRIME_PSEUDONYM_PREFIX) {
- struct eap_sim_pseudonym *p =
- eap_sim_db_get_pseudonym(data, identity, identity_len);
- return p ? 0 : -1;
- }
-
- if (identity[0] == EAP_SIM_REAUTH_ID_PREFIX ||
- identity[0] == EAP_AKA_REAUTH_ID_PREFIX ||
- identity[0] == EAP_AKA_PRIME_REAUTH_ID_PREFIX) {
- struct eap_sim_reauth *r =
- eap_sim_db_get_reauth(data, identity, identity_len);
- return r ? 0 : -1;
- }
-
- if (identity[0] != EAP_SIM_PERMANENT_PREFIX &&
- identity[0] != EAP_AKA_PERMANENT_PREFIX &&
- identity[0] != EAP_AKA_PRIME_PERMANENT_PREFIX) {
- /* Unknown identity prefix */
- return -1;
- }
-
- /* TODO: Should consider asking HLR/AuC gateway whether this permanent
- * identity is known. If it is, EAP-SIM/AKA can skip identity request.
- * In case of EAP-AKA, this would reduce number of needed round-trips.
- * Ideally, this would be done with one wait, i.e., just request
- * authentication data and store it for the next use. This would then
- * need to use similar pending-request functionality as the normal
- * request for authentication data at later phase.
- */
- return -1;
-}
-
-
static char * eap_sim_db_get_next(struct eap_sim_db_data *data, char prefix)
{
char *id, *pos, *end;
@@ -853,7 +965,7 @@ static char * eap_sim_db_get_next(struct eap_sim_db_data *data, char prefix)
/**
* eap_sim_db_get_next_pseudonym - EAP-SIM DB: Get next pseudonym
- * @priv: Private data pointer from eap_sim_db_init()
+ * @data: Private data pointer from eap_sim_db_init()
* @method: EAP method (SIM/AKA/AKA')
* Returns: Next pseudonym (allocated string) or %NULL on failure
*
@@ -862,9 +974,9 @@ static char * eap_sim_db_get_next(struct eap_sim_db_data *data, char prefix)
* with eap_sim_db_add_pseudonym() once the authentication has been completed
* successfully. Caller is responsible for freeing the returned buffer.
*/
-char * eap_sim_db_get_next_pseudonym(void *priv, enum eap_sim_db_method method)
+char * eap_sim_db_get_next_pseudonym(struct eap_sim_db_data *data,
+ enum eap_sim_db_method method)
{
- struct eap_sim_db_data *data = priv;
char prefix = EAP_SIM_REAUTH_ID_PREFIX;
switch (method) {
@@ -885,7 +997,7 @@ char * eap_sim_db_get_next_pseudonym(void *priv, enum eap_sim_db_method method)
/**
* eap_sim_db_get_next_reauth_id - EAP-SIM DB: Get next reauth_id
- * @priv: Private data pointer from eap_sim_db_init()
+ * @data: Private data pointer from eap_sim_db_init()
* @method: EAP method (SIM/AKA/AKA')
* Returns: Next reauth_id (allocated string) or %NULL on failure
*
@@ -895,9 +1007,9 @@ char * eap_sim_db_get_next_pseudonym(void *priv, enum eap_sim_db_method method)
* has been completed successfully. Caller is responsible for freeing the
* returned buffer.
*/
-char * eap_sim_db_get_next_reauth_id(void *priv, enum eap_sim_db_method method)
+char * eap_sim_db_get_next_reauth_id(struct eap_sim_db_data *data,
+ enum eap_sim_db_method method)
{
- struct eap_sim_db_data *data = priv;
char prefix = EAP_SIM_REAUTH_ID_PREFIX;
switch (method) {
@@ -918,9 +1030,8 @@ char * eap_sim_db_get_next_reauth_id(void *priv, enum eap_sim_db_method method)
/**
* eap_sim_db_add_pseudonym - EAP-SIM DB: Add new pseudonym
- * @priv: Private data pointer from eap_sim_db_init()
- * @identity: Identity of the user (may be permanent identity or pseudonym)
- * @identity_len: Length of identity
+ * @data: Private data pointer from eap_sim_db_init()
+ * @permanent: Permanent username
* @pseudonym: Pseudonym for this user. This needs to be an allocated buffer,
* e.g., return value from eap_sim_db_get_next_pseudonym(). Caller must not
* free it.
@@ -929,20 +1040,22 @@ char * eap_sim_db_get_next_reauth_id(void *priv, enum eap_sim_db_method method)
* This function adds a new pseudonym for EAP-SIM user. EAP-SIM DB is
* responsible of freeing pseudonym buffer once it is not needed anymore.
*/
-int eap_sim_db_add_pseudonym(void *priv, const u8 *identity,
- size_t identity_len, char *pseudonym)
+int eap_sim_db_add_pseudonym(struct eap_sim_db_data *data,
+ const char *permanent, char *pseudonym)
{
- struct eap_sim_db_data *data = priv;
struct eap_sim_pseudonym *p;
- wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Add pseudonym for identity",
- identity, identity_len);
- wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pseudonym: %s", pseudonym);
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Add pseudonym '%s' for permanent "
+ "username '%s'", pseudonym, permanent);
/* TODO: could store last two pseudonyms */
- p = eap_sim_db_get_pseudonym(data, identity, identity_len);
- if (p == NULL)
- p = eap_sim_db_get_pseudonym_id(data, identity, identity_len);
-
+#ifdef CONFIG_SQLITE
+ if (data->sqlite_db)
+ return db_add_pseudonym(data, permanent, pseudonym);
+#endif /* CONFIG_SQLITE */
+ for (p = data->pseudonyms; p; p = p->next) {
+ if (os_strcmp(permanent, p->permanent) == 0)
+ break;
+ }
if (p) {
wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous "
"pseudonym: %s", p->pseudonym);
@@ -958,14 +1071,12 @@ int eap_sim_db_add_pseudonym(void *priv, const u8 *identity,
}
p->next = data->pseudonyms;
- p->identity = os_malloc(identity_len);
- if (p->identity == NULL) {
+ p->permanent = os_strdup(permanent);
+ if (p->permanent == NULL) {
os_free(p);
os_free(pseudonym);
return -1;
}
- os_memcpy(p->identity, identity, identity_len);
- p->identity_len = identity_len;
p->pseudonym = pseudonym;
data->pseudonyms = p;
@@ -975,18 +1086,16 @@ int eap_sim_db_add_pseudonym(void *priv, const u8 *identity,
static struct eap_sim_reauth *
-eap_sim_db_add_reauth_data(struct eap_sim_db_data *data, const u8 *identity,
- size_t identity_len, char *reauth_id, u16 counter)
+eap_sim_db_add_reauth_data(struct eap_sim_db_data *data,
+ const char *permanent,
+ char *reauth_id, u16 counter)
{
struct eap_sim_reauth *r;
- wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Add reauth_id for identity",
- identity, identity_len);
- wpa_printf(MSG_DEBUG, "EAP-SIM DB: reauth_id: %s", reauth_id);
-
- r = eap_sim_db_get_reauth(data, identity, identity_len);
- if (r == NULL)
- r = eap_sim_db_get_reauth_id(data, identity, identity_len);
+ for (r = data->reauths; r; r = r->next) {
+ if (os_strcmp(r->permanent, permanent) == 0)
+ break;
+ }
if (r) {
wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous "
@@ -1001,14 +1110,12 @@ eap_sim_db_add_reauth_data(struct eap_sim_db_data *data, const u8 *identity,
}
r->next = data->reauths;
- r->identity = os_malloc(identity_len);
- if (r->identity == NULL) {
+ r->permanent = os_strdup(permanent);
+ if (r->permanent == NULL) {
os_free(r);
os_free(reauth_id);
return NULL;
}
- os_memcpy(r->identity, identity, identity_len);
- r->identity_len = identity_len;
r->reauth_id = reauth_id;
data->reauths = r;
wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new reauth entry");
@@ -1023,7 +1130,7 @@ eap_sim_db_add_reauth_data(struct eap_sim_db_data *data, const u8 *identity,
/**
* eap_sim_db_add_reauth - EAP-SIM DB: Add new re-authentication entry
* @priv: Private data pointer from eap_sim_db_init()
- * @identity: Identity of the user (may be permanent identity or pseudonym)
+ * @permanent: Permanent username
* @identity_len: Length of identity
* @reauth_id: reauth_id for this user. This needs to be an allocated buffer,
* e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not
@@ -1036,20 +1143,24 @@ eap_sim_db_add_reauth_data(struct eap_sim_db_data *data, const u8 *identity,
* EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed
* anymore.
*/
-int eap_sim_db_add_reauth(void *priv, const u8 *identity,
- size_t identity_len, char *reauth_id, u16 counter,
- const u8 *mk)
+int eap_sim_db_add_reauth(struct eap_sim_db_data *data, const char *permanent,
+ char *reauth_id, u16 counter, const u8 *mk)
{
- struct eap_sim_db_data *data = priv;
struct eap_sim_reauth *r;
- r = eap_sim_db_add_reauth_data(data, identity, identity_len, reauth_id,
- counter);
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Add reauth_id '%s' for permanent "
+ "identity '%s'", reauth_id, permanent);
+
+#ifdef CONFIG_SQLITE
+ if (data->sqlite_db)
+ return db_add_reauth(data, permanent, reauth_id, counter, mk,
+ NULL, NULL, NULL);
+#endif /* CONFIG_SQLITE */
+ r = eap_sim_db_add_reauth_data(data, permanent, reauth_id, counter);
if (r == NULL)
return -1;
os_memcpy(r->mk, mk, EAP_SIM_MK_LEN);
- r->aka_prime = 0;
return 0;
}
@@ -1058,9 +1169,8 @@ int eap_sim_db_add_reauth(void *priv, const u8 *identity,
#ifdef EAP_SERVER_AKA_PRIME
/**
* eap_sim_db_add_reauth_prime - EAP-AKA' DB: Add new re-authentication entry
- * @priv: Private data pointer from eap_sim_db_init()
- * @identity: Identity of the user (may be permanent identity or pseudonym)
- * @identity_len: Length of identity
+ * @data: Private data pointer from eap_sim_db_init()
+ * @permanent: Permanent username
* @reauth_id: reauth_id for this user. This needs to be an allocated buffer,
* e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not
* free it.
@@ -1074,20 +1184,25 @@ int eap_sim_db_add_reauth(void *priv, const u8 *identity,
* EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed
* anymore.
*/
-int eap_sim_db_add_reauth_prime(void *priv, const u8 *identity,
- size_t identity_len, char *reauth_id,
- u16 counter, const u8 *k_encr, const u8 *k_aut,
- const u8 *k_re)
+int eap_sim_db_add_reauth_prime(struct eap_sim_db_data *data,
+ const char *permanent, char *reauth_id,
+ u16 counter, const u8 *k_encr,
+ const u8 *k_aut, const u8 *k_re)
{
- struct eap_sim_db_data *data = priv;
struct eap_sim_reauth *r;
- r = eap_sim_db_add_reauth_data(data, identity, identity_len, reauth_id,
- counter);
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Add reauth_id '%s' for permanent "
+ "identity '%s'", reauth_id, permanent);
+
+#ifdef CONFIG_SQLITE
+ if (data->sqlite_db)
+ return db_add_reauth(data, permanent, reauth_id, counter, NULL,
+ k_encr, k_aut, k_re);
+#endif /* CONFIG_SQLITE */
+ r = eap_sim_db_add_reauth_data(data, permanent, reauth_id, counter);
if (r == NULL)
return -1;
- r->aka_prime = 1;
os_memcpy(r->k_encr, k_encr, EAP_SIM_K_ENCR_LEN);
os_memcpy(r->k_aut, k_aut, EAP_AKA_PRIME_K_AUT_LEN);
os_memcpy(r->k_re, k_re, EAP_AKA_PRIME_K_RE_LEN);
@@ -1099,66 +1214,75 @@ int eap_sim_db_add_reauth_prime(void *priv, const u8 *identity,
/**
* eap_sim_db_get_permanent - EAP-SIM DB: Get permanent identity
- * @priv: Private data pointer from eap_sim_db_init()
- * @identity: Identity of the user (may be permanent identity or pseudonym)
- * @identity_len: Length of identity
- * @len: Buffer for length of the returned permanent identity
- * Returns: Pointer to the permanent identity, or %NULL if not found
+ * @data: Private data pointer from eap_sim_db_init()
+ * @pseudonym: Pseudonym username
+ * Returns: Pointer to permanent username or %NULL if not found
*/
-const u8 * eap_sim_db_get_permanent(void *priv, const u8 *identity,
- size_t identity_len, size_t *len)
+const char *
+eap_sim_db_get_permanent(struct eap_sim_db_data *data, const char *pseudonym)
{
- struct eap_sim_db_data *data = priv;
struct eap_sim_pseudonym *p;
- if (identity == NULL)
- return NULL;
+#ifdef CONFIG_SQLITE
+ if (data->sqlite_db)
+ return db_get_pseudonym(data, pseudonym);
+#endif /* CONFIG_SQLITE */
- p = eap_sim_db_get_pseudonym(data, identity, identity_len);
- if (p == NULL)
- p = eap_sim_db_get_pseudonym_id(data, identity, identity_len);
- if (p == NULL)
- return NULL;
+ p = data->pseudonyms;
+ while (p) {
+ if (os_strcmp(p->pseudonym, pseudonym) == 0)
+ return p->permanent;
+ p = p->next;
+ }
- *len = p->identity_len;
- return p->identity;
+ return NULL;
}
/**
* eap_sim_db_get_reauth_entry - EAP-SIM DB: Get re-authentication entry
- * @priv: Private data pointer from eap_sim_db_init()
- * @identity: Identity of the user (may be permanent identity, pseudonym, or
- * reauth_id)
- * @identity_len: Length of identity
+ * @data: Private data pointer from eap_sim_db_init()
+ * @reauth_id: Fast re-authentication username
* Returns: Pointer to the re-auth entry, or %NULL if not found
*/
struct eap_sim_reauth *
-eap_sim_db_get_reauth_entry(void *priv, const u8 *identity,
- size_t identity_len)
+eap_sim_db_get_reauth_entry(struct eap_sim_db_data *data,
+ const char *reauth_id)
{
- struct eap_sim_db_data *data = priv;
struct eap_sim_reauth *r;
- if (identity == NULL)
- return NULL;
- r = eap_sim_db_get_reauth(data, identity, identity_len);
- if (r == NULL)
- r = eap_sim_db_get_reauth_id(data, identity, identity_len);
+#ifdef CONFIG_SQLITE
+ if (data->sqlite_db)
+ return db_get_reauth(data, reauth_id);
+#endif /* CONFIG_SQLITE */
+
+ r = data->reauths;
+ while (r) {
+ if (os_strcmp(r->reauth_id, reauth_id) == 0)
+ break;
+ r = r->next;
+ }
+
return r;
}
/**
* eap_sim_db_remove_reauth - EAP-SIM DB: Remove re-authentication entry
- * @priv: Private data pointer from eap_sim_db_init()
+ * @data: Private data pointer from eap_sim_db_init()
* @reauth: Pointer to re-authentication entry from
* eap_sim_db_get_reauth_entry()
*/
-void eap_sim_db_remove_reauth(void *priv, struct eap_sim_reauth *reauth)
+void eap_sim_db_remove_reauth(struct eap_sim_db_data *data,
+ struct eap_sim_reauth *reauth)
{
- struct eap_sim_db_data *data = priv;
struct eap_sim_reauth *r, *prev = NULL;
+#ifdef CONFIG_SQLITE
+ if (data->sqlite_db) {
+ db_remove_reauth(data, reauth);
+ return;
+ }
+#endif /* CONFIG_SQLITE */
r = data->reauths;
while (r) {
if (r == reauth) {
@@ -1177,9 +1301,8 @@ void eap_sim_db_remove_reauth(void *priv, struct eap_sim_reauth *reauth)
/**
* eap_sim_db_get_aka_auth - Get AKA authentication values
- * @priv: Private data pointer from eap_sim_db_init()
- * @identity: User name identity
- * @identity_len: Length of identity in bytes
+ * @data: Private data pointer from eap_sim_db_init()
+ * @username: Permanent username (prefix | IMSI)
* @_rand: Buffer for RAND value
* @autn: Buffer for AUTN value
* @ik: Buffer for IK value
@@ -1192,9 +1315,6 @@ void eap_sim_db_remove_reauth(void *priv, struct eap_sim_reauth *reauth)
* case, the callback function registered with eap_sim_db_init() will be
* called once the results become available.
*
- * In most cases, the user name is '0' | IMSI, i.e., 0 followed by the IMSI in
- * ASCII format for EAP-AKA and '6' | IMSI for EAP-AKA'.
- *
* When using an external server for AKA authentication, this function can
* always start a request and return EAP_SIM_DB_PENDING immediately if
* authentication triplets are not available. Once the authentication data are
@@ -1203,41 +1323,29 @@ void eap_sim_db_remove_reauth(void *priv, struct eap_sim_reauth *reauth)
* eap_sim_db_get_aka_auth() function will then be called again and the newly
* received triplets will then be given to the caller.
*/
-int eap_sim_db_get_aka_auth(void *priv, const u8 *identity,
- size_t identity_len, u8 *_rand, u8 *autn, u8 *ik,
- u8 *ck, u8 *res, size_t *res_len,
- void *cb_session_ctx)
+int eap_sim_db_get_aka_auth(struct eap_sim_db_data *data, const char *username,
+ u8 *_rand, u8 *autn, u8 *ik, u8 *ck,
+ u8 *res, size_t *res_len, void *cb_session_ctx)
{
- struct eap_sim_db_data *data = priv;
struct eap_sim_db_pending *entry;
int len;
- size_t i;
char msg[40];
+ const char *imsi;
+ size_t imsi_len;
- if (identity_len < 2 || identity == NULL ||
- (identity[0] != EAP_AKA_PERMANENT_PREFIX &&
- identity[0] != EAP_AKA_PRIME_PERMANENT_PREFIX)) {
- wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
- identity, identity_len);
+ if (username == NULL ||
+ (username[0] != EAP_AKA_PERMANENT_PREFIX &&
+ username[0] != EAP_AKA_PRIME_PERMANENT_PREFIX) ||
+ username[1] == '\0' || os_strlen(username) > sizeof(entry->imsi)) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: unexpected username '%s'",
+ username);
return EAP_SIM_DB_FAILURE;
}
- identity++;
- identity_len--;
- for (i = 0; i < identity_len; i++) {
- if (identity[i] == '@') {
- identity_len = i;
- break;
- }
- }
- if (identity_len + 1 > sizeof(entry->imsi)) {
- wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
- identity, identity_len);
- return EAP_SIM_DB_FAILURE;
- }
- wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI",
- identity, identity_len);
+ imsi = username + 1;
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI '%s'",
+ imsi);
- entry = eap_sim_db_get_pending(data, identity, identity_len, 1);
+ entry = eap_sim_db_get_pending(data, imsi, 1);
if (entry) {
if (entry->state == FAILURE) {
os_free(entry);
@@ -1268,14 +1376,15 @@ int eap_sim_db_get_aka_auth(void *priv, const u8 *identity,
return EAP_SIM_DB_FAILURE;
}
+ imsi_len = os_strlen(imsi);
len = os_snprintf(msg, sizeof(msg), "AKA-REQ-AUTH ");
- if (len < 0 || len + identity_len >= sizeof(msg))
+ if (len < 0 || len + imsi_len >= sizeof(msg))
return EAP_SIM_DB_FAILURE;
- os_memcpy(msg + len, identity, identity_len);
- len += identity_len;
+ os_memcpy(msg + len, imsi, imsi_len);
+ len += imsi_len;
- wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: requesting AKA authentication "
- "data for IMSI", identity, identity_len);
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: requesting AKA authentication "
+ "data for IMSI '%s'", imsi);
if (eap_sim_db_send(data, msg, len) < 0)
return EAP_SIM_DB_FAILURE;
@@ -1285,8 +1394,7 @@ int eap_sim_db_get_aka_auth(void *priv, const u8 *identity,
os_get_time(&entry->timestamp);
entry->aka = 1;
- os_memcpy(entry->imsi, identity, identity_len);
- entry->imsi_len = identity_len;
+ os_strlcpy(entry->imsi, imsi, sizeof(entry->imsi));
entry->cb_session_ctx = cb_session_ctx;
entry->state = PENDING;
eap_sim_db_add_pending(data, entry);
@@ -1298,9 +1406,8 @@ int eap_sim_db_get_aka_auth(void *priv, const u8 *identity,
/**
* eap_sim_db_resynchronize - Resynchronize AKA AUTN
- * @priv: Private data pointer from eap_sim_db_init()
- * @identity: User name identity
- * @identity_len: Length of identity in bytes
+ * @data: Private data pointer from eap_sim_db_init()
+ * @username: Permanent username
* @auts: AUTS value from the peer
* @_rand: RAND value used in the rejected message
* Returns: 0 on success, -1 on failure
@@ -1311,43 +1418,35 @@ int eap_sim_db_get_aka_auth(void *priv, const u8 *identity,
* eap_sim_db_get_aka_auth() will be called again to to fetch updated
* RAND/AUTN values for the next challenge.
*/
-int eap_sim_db_resynchronize(void *priv, const u8 *identity,
- size_t identity_len, const u8 *auts,
- const u8 *_rand)
+int eap_sim_db_resynchronize(struct eap_sim_db_data *data,
+ const char *username,
+ const u8 *auts, const u8 *_rand)
{
- struct eap_sim_db_data *data = priv;
- size_t i;
+ const char *imsi;
+ size_t imsi_len;
- if (identity_len < 2 || identity == NULL ||
- (identity[0] != EAP_AKA_PERMANENT_PREFIX &&
- identity[0] != EAP_AKA_PRIME_PERMANENT_PREFIX)) {
- wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
- identity, identity_len);
- return -1;
- }
- identity++;
- identity_len--;
- for (i = 0; i < identity_len; i++) {
- if (identity[i] == '@') {
- identity_len = i;
- break;
- }
- }
- if (identity_len > 20) {
- wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
- identity, identity_len);
+ if (username == NULL ||
+ (username[0] != EAP_AKA_PERMANENT_PREFIX &&
+ username[0] != EAP_AKA_PRIME_PERMANENT_PREFIX) ||
+ username[1] == '\0' || os_strlen(username) > 20) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: unexpected username '%s'",
+ username);
return -1;
}
+ imsi = username + 1;
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI '%s'",
+ imsi);
if (data->sock >= 0) {
char msg[100];
int len, ret;
+ imsi_len = os_strlen(imsi);
len = os_snprintf(msg, sizeof(msg), "AKA-AUTS ");
- if (len < 0 || len + identity_len >= sizeof(msg))
+ if (len < 0 || len + imsi_len >= sizeof(msg))
return -1;
- os_memcpy(msg + len, identity, identity_len);
- len += identity_len;
+ os_memcpy(msg + len, imsi, imsi_len);
+ len += imsi_len;
ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
@@ -1361,11 +1460,42 @@ int eap_sim_db_resynchronize(void *priv, const u8 *identity,
len += ret;
len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
_rand, EAP_AKA_RAND_LEN);
- wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: reporting AKA AUTS for "
- "IMSI", identity, identity_len);
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: reporting AKA AUTS for "
+ "IMSI '%s'", imsi);
if (eap_sim_db_send(data, msg, len) < 0)
return -1;
}
return 0;
}
+
+
+/**
+ * sim_get_username - Extract username from SIM identity
+ * @identity: Identity
+ * @identity_len: Identity length
+ * Returns: Allocated buffer with the username part of the identity
+ *
+ * Caller is responsible for freeing the returned buffer with os_free().
+ */
+char * sim_get_username(const u8 *identity, size_t identity_len)
+{
+ char *username;
+ size_t pos;
+
+ if (identity == NULL)
+ return NULL;
+
+ for (pos = 0; pos < identity_len; pos++) {
+ if (identity[pos] == '@' || identity[pos] == '\0')
+ break;
+ }
+
+ username = os_malloc(pos + 1);
+ if (username == NULL)
+ return NULL;
+ os_memcpy(username, identity, pos);
+ username[pos] = '\0';
+
+ return username;
+}
diff --git a/src/eap_server/eap_sim_db.h b/src/eap_server/eap_sim_db.h
index 1f6375a..53a1a7c 100644
--- a/src/eap_server/eap_sim_db.h
+++ b/src/eap_server/eap_sim_db.h
@@ -28,50 +28,47 @@ enum eap_sim_db_method {
EAP_SIM_DB_AKA_PRIME
};
-void * eap_sim_db_init(const char *config,
- void (*get_complete_cb)(void *ctx, void *session_ctx),
- void *ctx);
+struct eap_sim_db_data;
+
+struct eap_sim_db_data *
+eap_sim_db_init(const char *config,
+ void (*get_complete_cb)(void *ctx, void *session_ctx),
+ void *ctx);
void eap_sim_db_deinit(void *priv);
-int eap_sim_db_get_gsm_triplets(void *priv, const u8 *identity,
- size_t identity_len, int max_chal,
+int eap_sim_db_get_gsm_triplets(struct eap_sim_db_data *data,
+ const char *username, int max_chal,
u8 *_rand, u8 *kc, u8 *sres,
void *cb_session_ctx);
#define EAP_SIM_DB_FAILURE -1
#define EAP_SIM_DB_PENDING -2
-int eap_sim_db_identity_known(void *priv, const u8 *identity,
- size_t identity_len);
-
-char * eap_sim_db_get_next_pseudonym(void *priv,
+char * eap_sim_db_get_next_pseudonym(struct eap_sim_db_data *data,
enum eap_sim_db_method method);
-char * eap_sim_db_get_next_reauth_id(void *priv,
+char * eap_sim_db_get_next_reauth_id(struct eap_sim_db_data *data,
enum eap_sim_db_method method);
-int eap_sim_db_add_pseudonym(void *priv, const u8 *identity,
- size_t identity_len, char *pseudonym);
+int eap_sim_db_add_pseudonym(struct eap_sim_db_data *data,
+ const char *permanent, char *pseudonym);
-int eap_sim_db_add_reauth(void *priv, const u8 *identity,
- size_t identity_len, char *reauth_id, u16 counter,
- const u8 *mk);
-int eap_sim_db_add_reauth_prime(void *priv, const u8 *identity,
- size_t identity_len, char *reauth_id,
- u16 counter, const u8 *k_encr, const u8 *k_aut,
- const u8 *k_re);
+int eap_sim_db_add_reauth(struct eap_sim_db_data *data, const char *permanent,
+ char *reauth_id, u16 counter, const u8 *mk);
+int eap_sim_db_add_reauth_prime(struct eap_sim_db_data *data,
+ const char *permanent,
+ char *reauth_id, u16 counter, const u8 *k_encr,
+ const u8 *k_aut, const u8 *k_re);
-const u8 * eap_sim_db_get_permanent(void *priv, const u8 *identity,
- size_t identity_len, size_t *len);
+const char * eap_sim_db_get_permanent(struct eap_sim_db_data *data,
+ const char *pseudonym);
struct eap_sim_reauth {
struct eap_sim_reauth *next;
- u8 *identity;
- size_t identity_len;
- char *reauth_id;
+ char *permanent; /* Permanent username */
+ char *reauth_id; /* Fast re-authentication username */
u16 counter;
- int aka_prime;
u8 mk[EAP_SIM_MK_LEN];
u8 k_encr[EAP_SIM_K_ENCR_LEN];
u8 k_aut[EAP_AKA_PRIME_K_AUT_LEN];
@@ -79,18 +76,20 @@ struct eap_sim_reauth {
};
struct eap_sim_reauth *
-eap_sim_db_get_reauth_entry(void *priv, const u8 *identity,
- size_t identity_len);
+eap_sim_db_get_reauth_entry(struct eap_sim_db_data *data,
+ const char *reauth_id);
-void eap_sim_db_remove_reauth(void *priv, struct eap_sim_reauth *reauth);
+void eap_sim_db_remove_reauth(struct eap_sim_db_data *data,
+ struct eap_sim_reauth *reauth);
-int eap_sim_db_get_aka_auth(void *priv, const u8 *identity,
- size_t identity_len, u8 *_rand, u8 *autn, u8 *ik,
- u8 *ck, u8 *res, size_t *res_len,
- void *cb_session_ctx);
+int eap_sim_db_get_aka_auth(struct eap_sim_db_data *data, const char *username,
+ u8 *_rand, u8 *autn, u8 *ik, u8 *ck,
+ u8 *res, size_t *res_len, void *cb_session_ctx);
-int eap_sim_db_resynchronize(void *priv, const u8 *identity,
- size_t identity_len, const u8 *auts,
+int eap_sim_db_resynchronize(struct eap_sim_db_data *data,
+ const char *username, const u8 *auts,
const u8 *_rand);
+char * sim_get_username(const u8 *identity, size_t identity_len);
+
#endif /* EAP_SIM_DB_H */
diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c
index e3bfa38..851cf49 100644
--- a/src/eapol_supp/eapol_supp_sm.c
+++ b/src/eapol_supp/eapol_supp_sm.c
@@ -1825,6 +1825,15 @@ static void eapol_sm_notify_status(void *ctx, const char *status,
}
+static void eapol_sm_set_anon_id(void *ctx, const u8 *id, size_t len)
+{
+ struct eapol_sm *sm = ctx;
+
+ if (sm->ctx->set_anon_id)
+ sm->ctx->set_anon_id(sm->ctx->ctx, id, len);
+}
+
+
static struct eapol_callbacks eapol_cb =
{
eapol_sm_get_config,
@@ -1838,7 +1847,8 @@ static struct eapol_callbacks eapol_cb =
eapol_sm_notify_pending,
eapol_sm_eap_param_needed,
eapol_sm_notify_cert,
- eapol_sm_notify_status
+ eapol_sm_notify_status,
+ eapol_sm_set_anon_id
};
diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h
index d2a4b94..c4b87da 100644
--- a/src/eapol_supp/eapol_supp_sm.h
+++ b/src/eapol_supp/eapol_supp_sm.h
@@ -239,6 +239,14 @@ struct eapol_ctx {
*/
void (*status_cb)(void *ctx, const char *status,
const char *parameter);
+
+ /**
+ * set_anon_id - Set or add anonymous identity
+ * @ctx: eapol_ctx from eap_peer_sm_init() call
+ * @id: Anonymous identity (e.g., EAP-SIM pseudonym)
+ * @len: Length of anonymous identity in octets
+ */
+ void (*set_anon_id)(void *ctx, const u8 *id, size_t len);
};
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index df24c64..d26654b 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -30,6 +30,9 @@ static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p,
for (i = 0; i < p2p->num_groups; i++) {
struct p2p_group *g = p2p->groups[i];
struct wpabuf *ie;
+ if (os_memcmp(p2p_group_get_interface_addr(g),
+ p2p->inv_bssid, ETH_ALEN) != 0)
+ continue;
ie = p2p_group_get_wfd_ie(g);
if (ie) {
wfd_ie = ie;
@@ -101,8 +104,8 @@ static struct wpabuf * p2p_build_invitation_resp(struct p2p_data *p2p,
for (i = 0; i < p2p->num_groups; i++) {
struct p2p_group *g = p2p->groups[i];
struct wpabuf *ie;
- if (!p2p_group_is_group_id_match(g, group_bssid,
- ETH_ALEN))
+ if (os_memcmp(p2p_group_get_interface_addr(g),
+ group_bssid, ETH_ALEN) != 0)
continue;
ie = p2p_group_get_wfd_ie(g);
if (ie) {
diff --git a/src/rsn_supp/peerkey.c b/src/rsn_supp/peerkey.c
index 5e4872e..f2bac34 100644
--- a/src/rsn_supp/peerkey.c
+++ b/src/rsn_supp/peerkey.c
@@ -270,12 +270,7 @@ static int wpa_supplicant_process_smk_m2(
/* Include only the selected cipher in pairwise cipher suite */
WPA_PUT_LE16(pos, 1);
pos += 2;
- if (cipher == WPA_CIPHER_CCMP)
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
- else if (cipher == WPA_CIPHER_GCMP)
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP);
- else if (cipher == WPA_CIPHER_TKIP)
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
+ RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN, cipher));
pos += RSN_SELECTOR_LEN;
hdr->len = (pos - peerkey->rsnie_p) - 2;
@@ -1063,22 +1058,8 @@ int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer)
count_pos = pos;
pos += 2;
- count = 0;
- if (sm->allowed_pairwise_cipher & WPA_CIPHER_CCMP) {
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
- pos += RSN_SELECTOR_LEN;
- count++;
- }
- if (sm->allowed_pairwise_cipher & WPA_CIPHER_GCMP) {
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP);
- pos += RSN_SELECTOR_LEN;
- count++;
- }
- if (sm->allowed_pairwise_cipher & WPA_CIPHER_TKIP) {
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
- pos += RSN_SELECTOR_LEN;
- count++;
- }
+ count = rsn_cipher_put_suites(pos, sm->allowed_pairwise_cipher);
+ pos += count * RSN_SELECTOR_LEN;
WPA_PUT_LE16(count_pos, count);
hdr->len = (pos - peerkey->rsnie_i) - 2;
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index bcd5951..5cf32df 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -520,33 +520,23 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
"WPA: Installing PTK to the driver");
- switch (sm->pairwise_cipher) {
- case WPA_CIPHER_CCMP:
- alg = WPA_ALG_CCMP;
- keylen = 16;
- rsclen = 6;
- break;
- case WPA_CIPHER_GCMP:
- alg = WPA_ALG_GCMP;
- keylen = 16;
- rsclen = 6;
- break;
- case WPA_CIPHER_TKIP:
- alg = WPA_ALG_TKIP;
- keylen = 32;
- rsclen = 6;
- break;
- case WPA_CIPHER_NONE:
+ if (sm->pairwise_cipher == WPA_CIPHER_NONE) {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Pairwise Cipher "
"Suite: NONE - do not use pairwise keys");
return 0;
- default:
+ }
+
+ if (!wpa_cipher_valid_pairwise(sm->pairwise_cipher)) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Unsupported pairwise cipher %d",
sm->pairwise_cipher);
return -1;
}
+ alg = wpa_cipher_to_alg(sm->pairwise_cipher);
+ keylen = wpa_cipher_key_len(sm->pairwise_cipher);
+ rsclen = wpa_cipher_rsc_len(sm->pairwise_cipher);
+
if (sm->proto == WPA_PROTO_RSN) {
key_rsc = null_rsc;
} else {
@@ -579,63 +569,25 @@ static int wpa_supplicant_check_group_cipher(struct wpa_sm *sm,
int *key_rsc_len,
enum wpa_alg *alg)
{
- int ret = 0;
+ int klen;
- switch (group_cipher) {
- case WPA_CIPHER_CCMP:
- if (keylen != 16 || maxkeylen < 16) {
- ret = -1;
- break;
- }
- *key_rsc_len = 6;
- *alg = WPA_ALG_CCMP;
- break;
- case WPA_CIPHER_GCMP:
- if (keylen != 16 || maxkeylen < 16) {
- ret = -1;
- break;
- }
- *key_rsc_len = 6;
- *alg = WPA_ALG_GCMP;
- break;
- case WPA_CIPHER_TKIP:
- if (keylen != 32 || maxkeylen < 32) {
- ret = -1;
- break;
- }
- *key_rsc_len = 6;
- *alg = WPA_ALG_TKIP;
- break;
- case WPA_CIPHER_WEP104:
- if (keylen != 13 || maxkeylen < 13) {
- ret = -1;
- break;
- }
- *key_rsc_len = 0;
- *alg = WPA_ALG_WEP;
- break;
- case WPA_CIPHER_WEP40:
- if (keylen != 5 || maxkeylen < 5) {
- ret = -1;
- break;
- }
- *key_rsc_len = 0;
- *alg = WPA_ALG_WEP;
- break;
- default:
+ *alg = wpa_cipher_to_alg(group_cipher);
+ if (*alg == WPA_ALG_NONE) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Unsupported Group Cipher %d",
group_cipher);
return -1;
}
+ *key_rsc_len = wpa_cipher_rsc_len(group_cipher);
- if (ret < 0 ) {
+ klen = wpa_cipher_key_len(group_cipher);
+ if (keylen != klen || maxkeylen < klen) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Unsupported %s Group Cipher key length %d (%d)",
wpa_cipher_txt(group_cipher), keylen, maxkeylen);
+ return -1;
}
-
- return ret;
+ return 0;
}
@@ -1135,31 +1087,12 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
}
keylen = WPA_GET_BE16(key->key_length);
- switch (sm->pairwise_cipher) {
- case WPA_CIPHER_CCMP:
- if (keylen != 16) {
- wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
- "WPA: Invalid CCMP key length %d (src=" MACSTR
- ")", keylen, MAC2STR(sm->bssid));
- goto failed;
- }
- break;
- case WPA_CIPHER_GCMP:
- if (keylen != 16) {
- wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
- "WPA: Invalid GCMP key length %d (src=" MACSTR
- ")", keylen, MAC2STR(sm->bssid));
- goto failed;
- }
- break;
- case WPA_CIPHER_TKIP:
- if (keylen != 32) {
- wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
- "WPA: Invalid TKIP key length %d (src=" MACSTR
- ")", keylen, MAC2STR(sm->bssid));
- goto failed;
- }
- break;
+ if (keylen != wpa_cipher_key_len(sm->pairwise_cipher)) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "WPA: Invalid %s key length %d (src=" MACSTR
+ ")", wpa_cipher_txt(sm->pairwise_cipher), keylen,
+ MAC2STR(sm->bssid));
+ goto failed;
}
if (wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info,
@@ -1880,25 +1813,6 @@ out:
#ifdef CONFIG_CTRL_IFACE
-static int wpa_cipher_bits(int cipher)
-{
- switch (cipher) {
- case WPA_CIPHER_CCMP:
- return 128;
- case WPA_CIPHER_GCMP:
- return 128;
- case WPA_CIPHER_TKIP:
- return 256;
- case WPA_CIPHER_WEP104:
- return 104;
- case WPA_CIPHER_WEP40:
- return 40;
- default:
- return 0;
- }
-}
-
-
static u32 wpa_key_mgmt_suite(struct wpa_sm *sm)
{
switch (sm->key_mgmt) {
@@ -1930,32 +1844,6 @@ static u32 wpa_key_mgmt_suite(struct wpa_sm *sm)
}
-static u32 wpa_cipher_suite(struct wpa_sm *sm, int cipher)
-{
- switch (cipher) {
- case WPA_CIPHER_CCMP:
- return (sm->proto == WPA_PROTO_RSN ?
- RSN_CIPHER_SUITE_CCMP : WPA_CIPHER_SUITE_CCMP);
- case WPA_CIPHER_GCMP:
- return RSN_CIPHER_SUITE_GCMP;
- case WPA_CIPHER_TKIP:
- return (sm->proto == WPA_PROTO_RSN ?
- RSN_CIPHER_SUITE_TKIP : WPA_CIPHER_SUITE_TKIP);
- case WPA_CIPHER_WEP104:
- return (sm->proto == WPA_PROTO_RSN ?
- RSN_CIPHER_SUITE_WEP104 : WPA_CIPHER_SUITE_WEP104);
- case WPA_CIPHER_WEP40:
- return (sm->proto == WPA_PROTO_RSN ?
- RSN_CIPHER_SUITE_WEP40 : WPA_CIPHER_SUITE_WEP40);
- case WPA_CIPHER_NONE:
- return (sm->proto == WPA_PROTO_RSN ?
- RSN_CIPHER_SUITE_NONE : WPA_CIPHER_SUITE_NONE);
- default:
- return 0;
- }
-}
-
-
#define RSN_SUITE "%02x-%02x-%02x-%d"
#define RSN_SUITE_ARG(s) \
((s) >> 24) & 0xff, ((s) >> 16) & 0xff, ((s) >> 8) & 0xff, (s) & 0xff
@@ -2003,7 +1891,7 @@ int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen)
rsna ? "TRUE" : "FALSE",
rsna ? "TRUE" : "FALSE",
RSN_VERSION,
- wpa_cipher_bits(sm->group_cipher),
+ wpa_cipher_key_len(sm->group_cipher) * 8,
sm->dot11RSNAConfigPMKLifetime,
sm->dot11RSNAConfigPMKReauthThreshold,
sm->dot11RSNAConfigSATimeout);
@@ -2023,12 +1911,16 @@ int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen)
"dot11RSNAConfigNumberOfGTKSAReplayCounters=0\n"
"dot11RSNA4WayHandshakeFailures=%u\n",
RSN_SUITE_ARG(wpa_key_mgmt_suite(sm)),
- RSN_SUITE_ARG(wpa_cipher_suite(sm, sm->pairwise_cipher)),
- RSN_SUITE_ARG(wpa_cipher_suite(sm, sm->group_cipher)),
+ RSN_SUITE_ARG(wpa_cipher_to_suite(sm->proto,
+ sm->pairwise_cipher)),
+ RSN_SUITE_ARG(wpa_cipher_to_suite(sm->proto,
+ sm->group_cipher)),
pmkid_txt,
RSN_SUITE_ARG(wpa_key_mgmt_suite(sm)),
- RSN_SUITE_ARG(wpa_cipher_suite(sm, sm->pairwise_cipher)),
- RSN_SUITE_ARG(wpa_cipher_suite(sm, sm->group_cipher)),
+ RSN_SUITE_ARG(wpa_cipher_to_suite(sm->proto,
+ sm->pairwise_cipher)),
+ RSN_SUITE_ARG(wpa_cipher_to_suite(sm->proto,
+ sm->group_cipher)),
sm->dot11RSNA4WayHandshakeFailures);
if (ret >= 0 && (size_t) ret < buflen)
len += ret;
@@ -2717,33 +2609,10 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
os_memset(&igd, 0, sizeof(igd));
#endif /* CONFIG_IEEE80211W */
- switch (sm->group_cipher) {
- case WPA_CIPHER_CCMP:
- keylen = 16;
- gd.key_rsc_len = 6;
- gd.alg = WPA_ALG_CCMP;
- break;
- case WPA_CIPHER_GCMP:
- keylen = 16;
- gd.key_rsc_len = 6;
- gd.alg = WPA_ALG_GCMP;
- break;
- case WPA_CIPHER_TKIP:
- keylen = 32;
- gd.key_rsc_len = 6;
- gd.alg = WPA_ALG_TKIP;
- break;
- case WPA_CIPHER_WEP104:
- keylen = 13;
- gd.key_rsc_len = 0;
- gd.alg = WPA_ALG_WEP;
- break;
- case WPA_CIPHER_WEP40:
- keylen = 5;
- gd.key_rsc_len = 0;
- gd.alg = WPA_ALG_WEP;
- break;
- default:
+ keylen = wpa_cipher_key_len(sm->group_cipher);
+ gd.key_rsc_len = wpa_cipher_rsc_len(sm->group_cipher);
+ gd.alg = wpa_cipher_to_alg(sm->group_cipher);
+ if (gd.alg == WPA_ALG_NONE) {
wpa_printf(MSG_DEBUG, "Unsupported group cipher suite");
return -1;
}
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index bdf389b..2df060c 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -171,18 +171,16 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
pos = (u8 *) (rsnie + 1);
/* Group Suite Selector */
- if (sm->group_cipher == WPA_CIPHER_CCMP)
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
- else if (sm->group_cipher == WPA_CIPHER_GCMP)
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP);
- else if (sm->group_cipher == WPA_CIPHER_TKIP)
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
- else {
+ if (sm->group_cipher != WPA_CIPHER_CCMP &&
+ sm->group_cipher != WPA_CIPHER_GCMP &&
+ sm->group_cipher != WPA_CIPHER_TKIP) {
wpa_printf(MSG_WARNING, "FT: Invalid group cipher (%d)",
sm->group_cipher);
os_free(buf);
return NULL;
}
+ RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN,
+ sm->group_cipher));
pos += RSN_SELECTOR_LEN;
/* Pairwise Suite Count */
@@ -190,18 +188,14 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
pos += 2;
/* Pairwise Suite List */
- if (sm->pairwise_cipher == WPA_CIPHER_CCMP)
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
- else if (sm->pairwise_cipher == WPA_CIPHER_GCMP)
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP);
- else if (sm->pairwise_cipher == WPA_CIPHER_TKIP)
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
- else {
+ if (!wpa_cipher_valid_pairwise(sm->pairwise_cipher)) {
wpa_printf(MSG_WARNING, "FT: Invalid pairwise cipher (%d)",
sm->pairwise_cipher);
os_free(buf);
return NULL;
}
+ RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN,
+ sm->pairwise_cipher));
pos += RSN_SELECTOR_LEN;
/* Authenticated Key Management Suite Count */
@@ -327,25 +321,15 @@ static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid)
wpa_printf(MSG_DEBUG, "FT: Installing PTK to the driver.");
- switch (sm->pairwise_cipher) {
- case WPA_CIPHER_CCMP:
- alg = WPA_ALG_CCMP;
- keylen = 16;
- break;
- case WPA_CIPHER_GCMP:
- alg = WPA_ALG_GCMP;
- keylen = 16;
- break;
- case WPA_CIPHER_TKIP:
- alg = WPA_ALG_TKIP;
- keylen = 32;
- break;
- default:
+ if (!wpa_cipher_valid_pairwise(sm->pairwise_cipher)) {
wpa_printf(MSG_WARNING, "FT: Unsupported pairwise cipher %d",
sm->pairwise_cipher);
return -1;
}
+ alg = wpa_cipher_to_alg(sm->pairwise_cipher);
+ keylen = wpa_cipher_key_len(sm->pairwise_cipher);
+
if (wpa_sm_set_key(sm, alg, bssid, 0, 1, null_rsc,
sizeof(null_rsc), (u8 *) sm->ptk.tk1, keylen) < 0) {
wpa_printf(MSG_WARNING, "FT: Failed to set PTK to the driver");
@@ -579,33 +563,10 @@ static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem,
return -1;
}
- switch (sm->group_cipher) {
- case WPA_CIPHER_CCMP:
- keylen = 16;
- rsc_len = 6;
- alg = WPA_ALG_CCMP;
- break;
- case WPA_CIPHER_GCMP:
- keylen = 16;
- rsc_len = 6;
- alg = WPA_ALG_GCMP;
- break;
- case WPA_CIPHER_TKIP:
- keylen = 32;
- rsc_len = 6;
- alg = WPA_ALG_TKIP;
- break;
- case WPA_CIPHER_WEP104:
- keylen = 13;
- rsc_len = 0;
- alg = WPA_ALG_WEP;
- break;
- case WPA_CIPHER_WEP40:
- keylen = 5;
- rsc_len = 0;
- alg = WPA_ALG_WEP;
- break;
- default:
+ keylen = wpa_cipher_key_len(sm->group_cipher);
+ rsc_len = wpa_cipher_rsc_len(sm->group_cipher);
+ alg = wpa_cipher_to_alg(sm->group_cipher);
+ if (alg == WPA_ALG_NONE) {
wpa_printf(MSG_WARNING, "WPA: Unsupported Group Cipher %d",
sm->group_cipher);
return -1;
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index 16268d5..6a8f9f1 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -41,6 +41,7 @@ static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len,
{
u8 *pos;
struct wpa_ie_hdr *hdr;
+ u32 suite;
if (wpa_ie_len < sizeof(*hdr) + WPA_SELECTOR_LEN +
2 + WPA_SELECTOR_LEN + 2 + WPA_SELECTOR_LEN)
@@ -52,34 +53,26 @@ static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len,
WPA_PUT_LE16(hdr->version, WPA_VERSION);
pos = (u8 *) (hdr + 1);
- if (group_cipher == WPA_CIPHER_CCMP) {
- RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
- } else if (group_cipher == WPA_CIPHER_TKIP) {
- RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
- } else if (group_cipher == WPA_CIPHER_WEP104) {
- RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP104);
- } else if (group_cipher == WPA_CIPHER_WEP40) {
- RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP40);
- } else {
+ suite = wpa_cipher_to_suite(WPA_PROTO_WPA, group_cipher);
+ if (suite == 0) {
wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
group_cipher);
return -1;
}
+ RSN_SELECTOR_PUT(pos, suite);
pos += WPA_SELECTOR_LEN;
*pos++ = 1;
*pos++ = 0;
- if (pairwise_cipher == WPA_CIPHER_CCMP) {
- RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
- } else if (pairwise_cipher == WPA_CIPHER_TKIP) {
- RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
- } else if (pairwise_cipher == WPA_CIPHER_NONE) {
- RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE);
- } else {
+ suite = wpa_cipher_to_suite(WPA_PROTO_WPA, pairwise_cipher);
+ if (suite == 0 ||
+ (!wpa_cipher_valid_pairwise(pairwise_cipher) &&
+ pairwise_cipher != WPA_CIPHER_NONE)) {
wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
pairwise_cipher);
return -1;
}
+ RSN_SELECTOR_PUT(pos, suite);
pos += WPA_SELECTOR_LEN;
*pos++ = 1;
@@ -116,6 +109,7 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
u8 *pos;
struct rsn_ie_hdr *hdr;
u16 capab;
+ u32 suite;
if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN +
2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 +
@@ -130,38 +124,26 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
WPA_PUT_LE16(hdr->version, RSN_VERSION);
pos = (u8 *) (hdr + 1);
- if (group_cipher == WPA_CIPHER_CCMP) {
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
- } else if (group_cipher == WPA_CIPHER_GCMP) {
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP);
- } else if (group_cipher == WPA_CIPHER_TKIP) {
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
- } else if (group_cipher == WPA_CIPHER_WEP104) {
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP104);
- } else if (group_cipher == WPA_CIPHER_WEP40) {
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP40);
- } else {
+ suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher);
+ if (suite == 0) {
wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
group_cipher);
return -1;
}
+ RSN_SELECTOR_PUT(pos, suite);
pos += RSN_SELECTOR_LEN;
*pos++ = 1;
*pos++ = 0;
- if (pairwise_cipher == WPA_CIPHER_CCMP) {
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
- } else if (pairwise_cipher == WPA_CIPHER_GCMP) {
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP);
- } else if (pairwise_cipher == WPA_CIPHER_TKIP) {
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
- } else if (pairwise_cipher == WPA_CIPHER_NONE) {
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE);
- } else {
+ suite = wpa_cipher_to_suite(WPA_PROTO_RSN, pairwise_cipher);
+ if (suite == 0 ||
+ (!wpa_cipher_valid_pairwise(pairwise_cipher) &&
+ pairwise_cipher != WPA_CIPHER_NONE)) {
wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
pairwise_cipher);
return -1;
}
+ RSN_SELECTOR_PUT(pos, suite);
pos += RSN_SELECTOR_LEN;
*pos++ = 1;
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index eae00d8..4f58a92 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -1135,6 +1135,7 @@ SHA1OBJS += src/crypto/sha1-tlsprf.c
endif
endif
+MD5OBJS =
ifndef CONFIG_FIPS
MD5OBJS += src/crypto/md5.c
endif
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 580a82a..d326bef 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -35,6 +35,64 @@
#define WPA_BSS_IES_CHANGED_FLAG BIT(8)
+static void wpa_bss_set_hessid(struct wpa_bss *bss)
+{
+#ifdef CONFIG_INTERWORKING
+ const u8 *ie = wpa_bss_get_ie(bss, WLAN_EID_INTERWORKING);
+ if (ie == NULL || (ie[1] != 7 && ie[1] != 9)) {
+ os_memset(bss->hessid, 0, ETH_ALEN);
+ return;
+ }
+ if (ie[1] == 7)
+ os_memcpy(bss->hessid, ie + 3, ETH_ALEN);
+ else
+ os_memcpy(bss->hessid, ie + 5, ETH_ALEN);
+#endif /* CONFIG_INTERWORKING */
+}
+
+
+struct wpa_bss_anqp * wpa_bss_anqp_alloc(void)
+{
+ struct wpa_bss_anqp *anqp;
+ anqp = os_zalloc(sizeof(*anqp));
+ if (anqp == NULL)
+ return NULL;
+ anqp->users = 1;
+ return anqp;
+}
+
+
+static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp)
+{
+ if (anqp == NULL)
+ return;
+
+ anqp->users--;
+ if (anqp->users > 0) {
+ /* Another BSS entry holds a pointer to this ANQP info */
+ return;
+ }
+
+#ifdef CONFIG_INTERWORKING
+ wpabuf_free(anqp->venue_name);
+ wpabuf_free(anqp->network_auth_type);
+ wpabuf_free(anqp->roaming_consortium);
+ wpabuf_free(anqp->ip_addr_type_availability);
+ wpabuf_free(anqp->nai_realm);
+ wpabuf_free(anqp->anqp_3gpp);
+ wpabuf_free(anqp->domain_name);
+#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+ wpabuf_free(anqp->hs20_operator_friendly_name);
+ wpabuf_free(anqp->hs20_wan_metrics);
+ wpabuf_free(anqp->hs20_connection_capability);
+ wpabuf_free(anqp->hs20_operating_class);
+#endif /* CONFIG_HS20 */
+
+ os_free(anqp);
+}
+
+
static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
const char *reason)
{
@@ -45,21 +103,7 @@ static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
" SSID '%s' due to %s", bss->id, MAC2STR(bss->bssid),
wpa_ssid_txt(bss->ssid, bss->ssid_len), reason);
wpas_notify_bss_removed(wpa_s, bss->bssid, bss->id);
-#ifdef CONFIG_INTERWORKING
- wpabuf_free(bss->anqp_venue_name);
- wpabuf_free(bss->anqp_network_auth_type);
- wpabuf_free(bss->anqp_roaming_consortium);
- wpabuf_free(bss->anqp_ip_addr_type_availability);
- wpabuf_free(bss->anqp_nai_realm);
- wpabuf_free(bss->anqp_3gpp);
- wpabuf_free(bss->anqp_domain_name);
-#endif /* CONFIG_INTERWORKING */
-#ifdef CONFIG_HS20
- wpabuf_free(bss->hs20_operator_friendly_name);
- wpabuf_free(bss->hs20_wan_metrics);
- wpabuf_free(bss->hs20_connection_capability);
- wpabuf_free(bss->hs20_operating_class);
-#endif /* CONFIG_HS20 */
+ wpa_bss_anqp_free(bss->anqp);
os_free(bss);
}
@@ -186,6 +230,7 @@ static void wpa_bss_add(struct wpa_supplicant *wpa_s,
bss->ie_len = res->ie_len;
bss->beacon_ie_len = res->beacon_ie_len;
os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
+ wpa_bss_set_hessid(bss);
dl_list_add_tail(&wpa_s->bss, &bss->list);
dl_list_add_tail(&wpa_s->bss_id, &bss->list_id);
@@ -365,6 +410,8 @@ static void wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
}
dl_list_add(prev, &bss->list_id);
}
+ if (changes & WPA_BSS_IES_CHANGED_FLAG)
+ wpa_bss_set_hessid(bss);
dl_list_add_tail(&wpa_s->bss, &bss->list);
notify_bss_changes(wpa_s, changes, bss);
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index 65e962b..8a307cc 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -19,6 +19,25 @@ struct wpa_scan_res;
#define WPA_BSS_ASSOCIATED BIT(5)
#define WPA_BSS_ANQP_FETCH_TRIED BIT(6)
+struct wpa_bss_anqp {
+ unsigned int users;
+#ifdef CONFIG_INTERWORKING
+ struct wpabuf *venue_name;
+ struct wpabuf *network_auth_type;
+ struct wpabuf *roaming_consortium;
+ struct wpabuf *ip_addr_type_availability;
+ struct wpabuf *nai_realm;
+ struct wpabuf *anqp_3gpp;
+ struct wpabuf *domain_name;
+#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+ struct wpabuf *hs20_operator_friendly_name;
+ struct wpabuf *hs20_wan_metrics;
+ struct wpabuf *hs20_connection_capability;
+ struct wpabuf *hs20_operating_class;
+#endif /* CONFIG_HS20 */
+};
+
/**
* struct wpa_bss - BSS table
* @list: List entry for struct wpa_supplicant::bss
@@ -28,6 +47,7 @@ struct wpa_scan_res;
* @flags: information flags about the BSS/IBSS (WPA_BSS_*)
* @last_update_idx: Index of the last scan update
* @bssid: BSSID
+ * @hessid: HESSID
* @freq: frequency of the channel in MHz (e.g., 2412 = channel 1)
* @beacon_int: beacon interval in TUs (host byte order)
* @caps: capability information field in host byte order
@@ -50,6 +70,7 @@ struct wpa_bss {
unsigned int last_update_idx;
unsigned int flags;
u8 bssid[ETH_ALEN];
+ u8 hessid[ETH_ALEN];
u8 ssid[32];
size_t ssid_len;
int freq;
@@ -60,21 +81,7 @@ struct wpa_bss {
int level;
u64 tsf;
struct os_time last_update;
-#ifdef CONFIG_INTERWORKING
- struct wpabuf *anqp_venue_name;
- struct wpabuf *anqp_network_auth_type;
- struct wpabuf *anqp_roaming_consortium;
- struct wpabuf *anqp_ip_addr_type_availability;
- struct wpabuf *anqp_nai_realm;
- struct wpabuf *anqp_3gpp;
- struct wpabuf *anqp_domain_name;
-#endif /* CONFIG_INTERWORKING */
-#ifdef CONFIG_HS20
- struct wpabuf *hs20_operator_friendly_name;
- struct wpabuf *hs20_wan_metrics;
- struct wpabuf *hs20_connection_capability;
- struct wpabuf *hs20_operating_class;
-#endif /* CONFIG_HS20 */
+ struct wpa_bss_anqp *anqp;
size_t ie_len;
size_t beacon_ie_len;
/* followed by ie_len octets of IEs */
@@ -103,5 +110,6 @@ struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
u32 vendor_type);
int wpa_bss_get_max_rate(const struct wpa_bss *bss);
int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates);
+struct wpa_bss_anqp * wpa_bss_anqp_alloc(void);
#endif /* BSS_H */
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 4f0c43d..480c077 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -2792,27 +2792,28 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
#endif /* CONFIG_WIFI_DISPLAY */
#ifdef CONFIG_INTERWORKING
- if (mask & WPA_BSS_MASK_INTERNETW) {
+ if ((mask & WPA_BSS_MASK_INTERNETW) && bss->anqp) {
+ struct wpa_bss_anqp *anqp = bss->anqp;
pos = anqp_add_hex(pos, end, "anqp_venue_name",
- bss->anqp_venue_name);
+ anqp->venue_name);
pos = anqp_add_hex(pos, end, "anqp_network_auth_type",
- bss->anqp_network_auth_type);
+ anqp->network_auth_type);
pos = anqp_add_hex(pos, end, "anqp_roaming_consortium",
- bss->anqp_roaming_consortium);
+ anqp->roaming_consortium);
pos = anqp_add_hex(pos, end, "anqp_ip_addr_type_availability",
- bss->anqp_ip_addr_type_availability);
+ anqp->ip_addr_type_availability);
pos = anqp_add_hex(pos, end, "anqp_nai_realm",
- bss->anqp_nai_realm);
- pos = anqp_add_hex(pos, end, "anqp_3gpp", bss->anqp_3gpp);
+ anqp->nai_realm);
+ pos = anqp_add_hex(pos, end, "anqp_3gpp", anqp->anqp_3gpp);
pos = anqp_add_hex(pos, end, "anqp_domain_name",
- bss->anqp_domain_name);
+ anqp->domain_name);
#ifdef CONFIG_HS20
pos = anqp_add_hex(pos, end, "hs20_operator_friendly_name",
- bss->hs20_operator_friendly_name);
+ anqp->hs20_operator_friendly_name);
pos = anqp_add_hex(pos, end, "hs20_wan_metrics",
- bss->hs20_wan_metrics);
+ anqp->hs20_wan_metrics);
pos = anqp_add_hex(pos, end, "hs20_connection_capability",
- bss->hs20_connection_capability);
+ anqp->hs20_connection_capability);
#endif /* CONFIG_HS20 */
}
#endif /* CONFIG_INTERWORKING */
@@ -4381,6 +4382,7 @@ static int wpa_supplicant_driver_cmd(struct wpa_supplicant *wpa_s, char *cmd,
}
#endif
+
char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
char *buf, size_t *resp_len)
{
diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c
index 7d63c1b..03b8c7e 100644
--- a/wpa_supplicant/eapol_test.c
+++ b/wpa_supplicant/eapol_test.c
@@ -429,6 +429,37 @@ static void eapol_test_cert_cb(void *ctx, int depth, const char *subject,
}
+static void eapol_test_set_anon_id(void *ctx, const u8 *id, size_t len)
+{
+ struct eapol_test_data *e = ctx;
+ struct wpa_supplicant *wpa_s = e->wpa_s;
+ char *str;
+ int res;
+
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP method updated anonymous_identity",
+ id, len);
+
+ if (wpa_s->current_ssid == NULL)
+ return;
+
+ if (id == NULL) {
+ if (wpa_config_set(wpa_s->current_ssid, "anonymous_identity",
+ "NULL", 0) < 0)
+ return;
+ } else {
+ str = os_malloc(len * 2 + 1);
+ if (str == NULL)
+ return;
+ wpa_snprintf_hex(str, len * 2 + 1, id, len);
+ res = wpa_config_set(wpa_s->current_ssid, "anonymous_identity",
+ str, 0);
+ os_free(str);
+ if (res < 0)
+ return;
+ }
+}
+
+
static int test_eapol(struct eapol_test_data *e, struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
@@ -456,6 +487,7 @@ static int test_eapol(struct eapol_test_data *e, struct wpa_supplicant *wpa_s,
ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
ctx->cert_cb = eapol_test_cert_cb;
ctx->cert_in_cb = 1;
+ ctx->set_anon_id = eapol_test_set_anon_id;
wpa_s->eapol = eapol_sm_init(ctx);
if (wpa_s->eapol == NULL) {
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index c3acad4..bb870c0 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -1062,6 +1062,9 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid = NULL;
struct wpa_scan_results *scan_res;
int ap = 0;
+#ifndef CONFIG_NO_RANDOM_POOL
+ size_t i, num;
+#endif /* CONFIG_NO_RANDOM_POOL */
#ifdef CONFIG_AP
if (wpa_s->ap_iface)
@@ -1100,7 +1103,6 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
}
#ifndef CONFIG_NO_RANDOM_POOL
- size_t i, num;
num = scan_res->num;
if (num > 10)
num = 10;
diff --git a/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant/hs20_supplicant.c
index 2afa16c..0eb6119 100644
--- a/wpa_supplicant/hs20_supplicant.c
+++ b/wpa_supplicant/hs20_supplicant.c
@@ -110,10 +110,14 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
const u8 *pos = data;
u8 subtype;
struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa);
+ struct wpa_bss_anqp *anqp = NULL;
if (slen < 2)
return;
+ if (bss)
+ anqp = bss->anqp;
+
subtype = *pos++;
slen--;
@@ -130,9 +134,9 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
" Operator Friendly Name", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "oper friendly name", pos, slen);
- if (bss) {
- wpabuf_free(bss->hs20_operator_friendly_name);
- bss->hs20_operator_friendly_name =
+ if (anqp) {
+ wpabuf_free(anqp->hs20_operator_friendly_name);
+ anqp->hs20_operator_friendly_name =
wpabuf_alloc_copy(pos, slen);
}
break;
@@ -140,18 +144,18 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
" WAN Metrics", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "WAN Metrics", pos, slen);
- if (bss) {
- wpabuf_free(bss->hs20_wan_metrics);
- bss->hs20_wan_metrics = wpabuf_alloc_copy(pos, slen);
+ if (anqp) {
+ wpabuf_free(anqp->hs20_wan_metrics);
+ anqp->hs20_wan_metrics = wpabuf_alloc_copy(pos, slen);
}
break;
case HS20_STYPE_CONNECTION_CAPABILITY:
wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
" Connection Capability", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "conn capability", pos, slen);
- if (bss) {
- wpabuf_free(bss->hs20_connection_capability);
- bss->hs20_connection_capability =
+ if (anqp) {
+ wpabuf_free(anqp->hs20_connection_capability);
+ anqp->hs20_connection_capability =
wpabuf_alloc_copy(pos, slen);
}
break;
@@ -159,9 +163,9 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
" Operating Class", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "Operating Class", pos, slen);
- if (bss) {
- wpabuf_free(bss->hs20_operating_class);
- bss->hs20_operating_class =
+ if (anqp) {
+ wpabuf_free(anqp->hs20_operating_class);
+ anqp->hs20_operating_class =
wpabuf_alloc_copy(pos, slen);
}
break;
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index 7b5b20e..b362bcb 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -52,6 +52,18 @@ static void interworking_reconnect(struct wpa_supplicant *wpa_s)
}
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
+
+ if (wpa_s->last_scan_res_used > 0) {
+ struct os_time now;
+ os_get_time(&now);
+ if (now.sec - wpa_s->last_scan.sec <= 5) {
+ wpa_printf(MSG_DEBUG, "Interworking: Old scan results "
+ "are fresh - connect without new scan");
+ if (wpas_select_network_from_last_scan(wpa_s) == 0)
+ return;
+ }
+ }
+
wpa_supplicant_req_scan(wpa_s, 0, 0);
}
@@ -96,27 +108,101 @@ static void interworking_anqp_resp_cb(void *ctx, const u8 *dst,
}
+static int cred_with_roaming_consortium(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_cred *cred;
+
+ for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+ if (cred->roaming_consortium_len)
+ return 1;
+ }
+ return 0;
+}
+
+
+static int cred_with_3gpp(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_cred *cred;
+
+ for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+ if (cred->pcsc || cred->imsi)
+ return 1;
+ }
+ return 0;
+}
+
+
+static int cred_with_nai_realm(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_cred *cred;
+
+ for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+ if (cred->pcsc || cred->imsi)
+ continue;
+ if (!cred->eap_method)
+ return 1;
+ if (cred->realm && cred->roaming_consortium_len == 0)
+ return 1;
+ }
+ return 0;
+}
+
+
+static int cred_with_domain(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_cred *cred;
+
+ for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+ if (cred->domain || cred->pcsc || cred->imsi)
+ return 1;
+ }
+ return 0;
+}
+
+
+static int additional_roaming_consortiums(struct wpa_bss *bss)
+{
+ const u8 *ie;
+ ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM);
+ if (ie == NULL || ie[1] == 0)
+ return 0;
+ return ie[2]; /* Number of ANQP OIs */
+}
+
+
static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss)
{
struct wpabuf *buf;
int ret = 0;
int res;
- u16 info_ids[] = {
- ANQP_CAPABILITY_LIST,
- ANQP_VENUE_NAME,
- ANQP_NETWORK_AUTH_TYPE,
- ANQP_ROAMING_CONSORTIUM,
- ANQP_IP_ADDR_TYPE_AVAILABILITY,
- ANQP_NAI_REALM,
- ANQP_3GPP_CELLULAR_NETWORK,
- ANQP_DOMAIN_NAME
- };
+ u16 info_ids[8];
+ size_t num_info_ids = 0;
struct wpabuf *extra = NULL;
+ int all = wpa_s->fetch_all_anqp;
wpa_printf(MSG_DEBUG, "Interworking: ANQP Query Request to " MACSTR,
MAC2STR(bss->bssid));
+ info_ids[num_info_ids++] = ANQP_CAPABILITY_LIST;
+ if (all) {
+ info_ids[num_info_ids++] = ANQP_VENUE_NAME;
+ info_ids[num_info_ids++] = ANQP_NETWORK_AUTH_TYPE;
+ }
+ if (all || (cred_with_roaming_consortium(wpa_s) &&
+ additional_roaming_consortiums(bss)))
+ info_ids[num_info_ids++] = ANQP_ROAMING_CONSORTIUM;
+ if (all)
+ info_ids[num_info_ids++] = ANQP_IP_ADDR_TYPE_AVAILABILITY;
+ if (all || cred_with_nai_realm(wpa_s))
+ info_ids[num_info_ids++] = ANQP_NAI_REALM;
+ if (all || cred_with_3gpp(wpa_s))
+ info_ids[num_info_ids++] = ANQP_3GPP_CELLULAR_NETWORK;
+ if (all || cred_with_domain(wpa_s))
+ info_ids[num_info_ids++] = ANQP_DOMAIN_NAME;
+ wpa_hexdump(MSG_DEBUG, "Interworking: ANQP Query info",
+ (u8 *) info_ids, num_info_ids * 2);
+
#ifdef CONFIG_HS20
if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) {
u8 *len_pos;
@@ -131,16 +217,18 @@ static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s,
wpabuf_put_u8(extra, HS20_STYPE_QUERY_LIST);
wpabuf_put_u8(extra, 0); /* Reserved */
wpabuf_put_u8(extra, HS20_STYPE_CAPABILITY_LIST);
- wpabuf_put_u8(extra, HS20_STYPE_OPERATOR_FRIENDLY_NAME);
- wpabuf_put_u8(extra, HS20_STYPE_WAN_METRICS);
- wpabuf_put_u8(extra, HS20_STYPE_CONNECTION_CAPABILITY);
- wpabuf_put_u8(extra, HS20_STYPE_OPERATING_CLASS);
+ if (all) {
+ wpabuf_put_u8(extra,
+ HS20_STYPE_OPERATOR_FRIENDLY_NAME);
+ wpabuf_put_u8(extra, HS20_STYPE_WAN_METRICS);
+ wpabuf_put_u8(extra, HS20_STYPE_CONNECTION_CAPABILITY);
+ wpabuf_put_u8(extra, HS20_STYPE_OPERATING_CLASS);
+ }
gas_anqp_set_element_len(extra, len_pos);
}
#endif /* CONFIG_HS20 */
- buf = anqp_build_req(info_ids, sizeof(info_ids) / sizeof(info_ids[0]),
- extra);
+ buf = anqp_build_req(info_ids, num_info_ids, extra);
wpabuf_free(extra);
if (buf == NULL)
return -1;
@@ -648,8 +736,11 @@ static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
struct wpa_cred *cred;
struct wpa_ssid *ssid;
const u8 *ie;
+ int eap_type;
+ int res;
+ char prefix;
- if (bss->anqp_3gpp == NULL)
+ if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL)
return -1;
for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
@@ -680,7 +771,7 @@ static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
#ifdef PCSC_FUNCS
compare:
#endif /* PCSC_FUNCS */
- if (plmn_id_match(bss->anqp_3gpp, imsi, mnc_len))
+ if (plmn_id_match(bss->anqp->anqp_3gpp, imsi, mnc_len))
break;
}
if (cred == NULL)
@@ -709,14 +800,40 @@ static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
if (interworking_set_hs20_params(ssid) < 0)
goto fail;
- /* TODO: figure out whether to use EAP-SIM, EAP-AKA, or EAP-AKA' */
- if (wpa_config_set(ssid, "eap", "SIM", 0) < 0) {
- wpa_printf(MSG_DEBUG, "EAP-SIM not supported");
+ eap_type = EAP_TYPE_SIM;
+ if (cred->pcsc && wpa_s->scard && scard_supports_umts(wpa_s->scard))
+ eap_type = EAP_TYPE_AKA;
+ if (cred->eap_method && cred->eap_method[0].vendor == EAP_VENDOR_IETF) {
+ if (cred->eap_method[0].method == EAP_TYPE_SIM ||
+ cred->eap_method[0].method == EAP_TYPE_AKA ||
+ cred->eap_method[0].method == EAP_TYPE_AKA_PRIME)
+ eap_type = cred->eap_method[0].method;
+ }
+
+ switch (eap_type) {
+ case EAP_TYPE_SIM:
+ prefix = '1';
+ res = wpa_config_set(ssid, "eap", "SIM", 0);
+ break;
+ case EAP_TYPE_AKA:
+ prefix = '0';
+ res = wpa_config_set(ssid, "eap", "AKA", 0);
+ break;
+ case EAP_TYPE_AKA_PRIME:
+ prefix = '6';
+ res = wpa_config_set(ssid, "eap", "AKA'", 0);
+ break;
+ default:
+ res = -1;
+ break;
+ }
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG, "Selected EAP method (%d) not supported",
+ eap_type);
goto fail;
}
- if (cred->pcsc && wpa_s->scard && scard_supports_umts(wpa_s->scard))
- wpa_config_set(ssid, "eap", "AKA", 0);
- if (!cred->pcsc && set_root_nai(ssid, cred->imsi, '1') < 0) {
+
+ if (!cred->pcsc && set_root_nai(ssid, cred->imsi, prefix) < 0) {
wpa_printf(MSG_DEBUG, "Failed to set Root NAI");
goto fail;
}
@@ -835,7 +952,8 @@ static struct wpa_cred * interworking_credentials_available_roaming_consortium(
ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM);
- if (ie == NULL && bss->anqp_roaming_consortium == NULL)
+ if (ie == NULL &&
+ (bss->anqp == NULL || bss->anqp->roaming_consortium == NULL))
return NULL;
if (wpa_s->conf->cred == NULL)
@@ -845,7 +963,10 @@ static struct wpa_cred * interworking_credentials_available_roaming_consortium(
if (cred->roaming_consortium_len == 0)
continue;
- if (!roaming_consortium_match(ie, bss->anqp_roaming_consortium,
+ if (!roaming_consortium_match(ie,
+ bss->anqp ?
+ bss->anqp->roaming_consortium :
+ NULL,
cred->roaming_consortium,
cred->roaming_consortium_len))
continue;
@@ -1035,7 +1156,8 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
return interworking_connect_roaming_consortium(wpa_s, cred,
bss, ie);
- realm = nai_realm_parse(bss->anqp_nai_realm, &count);
+ realm = nai_realm_parse(bss->anqp ? bss->anqp->nai_realm : NULL,
+ &count);
if (realm == NULL) {
wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
"Realm list from " MACSTR, MAC2STR(bss->bssid));
@@ -1162,7 +1284,7 @@ static struct wpa_cred * interworking_credentials_available_3gpp(
int ret;
#ifdef INTERWORKING_3GPP
- if (bss->anqp_3gpp == NULL)
+ if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL)
return NULL;
for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
@@ -1195,7 +1317,7 @@ static struct wpa_cred * interworking_credentials_available_3gpp(
#endif /* PCSC_FUNCS */
wpa_printf(MSG_DEBUG, "Interworking: Parsing 3GPP info from "
MACSTR, MAC2STR(bss->bssid));
- ret = plmn_id_match(bss->anqp_3gpp, imsi, mnc_len);
+ ret = plmn_id_match(bss->anqp->anqp_3gpp, imsi, mnc_len);
wpa_printf(MSG_DEBUG, "PLMN match %sfound", ret ? "" : "not ");
if (ret) {
if (selected == NULL ||
@@ -1215,7 +1337,7 @@ static struct wpa_cred * interworking_credentials_available_realm(
struct nai_realm *realm;
u16 count, i;
- if (bss->anqp_nai_realm == NULL)
+ if (bss->anqp == NULL || bss->anqp->nai_realm == NULL)
return NULL;
if (wpa_s->conf->cred == NULL)
@@ -1223,7 +1345,7 @@ static struct wpa_cred * interworking_credentials_available_realm(
wpa_printf(MSG_DEBUG, "Interworking: Parsing NAI Realm list from "
MACSTR, MAC2STR(bss->bssid));
- realm = nai_realm_parse(bss->anqp_nai_realm, &count);
+ realm = nai_realm_parse(bss->anqp->nai_realm, &count);
if (realm == NULL) {
wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
"Realm list from " MACSTR, MAC2STR(bss->bssid));
@@ -1319,11 +1441,13 @@ static int interworking_home_sp(struct wpa_supplicant *wpa_s,
int mnc_len = 0;
if (cred->imsi)
imsi = cred->imsi;
+#ifdef CONFIG_PCSC
else if (cred->pcsc && wpa_s->conf->pcsc_reader &&
wpa_s->scard && wpa_s->imsi[0]) {
imsi = wpa_s->imsi;
mnc_len = wpa_s->mnc_len;
}
+#endif /* CONFIG_PCSC */
if (imsi && build_root_nai(nai, sizeof(nai), imsi, mnc_len, 0)
== 0) {
realm = os_strchr(nai, '@');
@@ -1402,7 +1526,8 @@ static void interworking_select_network(struct wpa_supplicant *wpa_s)
continue;
}
count++;
- res = interworking_home_sp(wpa_s, bss->anqp_domain_name);
+ res = interworking_home_sp(wpa_s, bss->anqp ?
+ bss->anqp->domain_name : NULL);
if (res > 0)
type = "home";
else if (res == 0)
@@ -1465,6 +1590,38 @@ static void interworking_select_network(struct wpa_supplicant *wpa_s)
}
+static struct wpa_bss_anqp *
+interworking_match_anqp_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+ struct wpa_bss *other;
+
+ if (is_zero_ether_addr(bss->hessid))
+ return NULL; /* Cannot be in the same homegenous ESS */
+
+ dl_list_for_each(other, &wpa_s->bss, struct wpa_bss, list) {
+ if (other == bss)
+ continue;
+ if (other->anqp == NULL)
+ continue;
+ if (!(other->flags & WPA_BSS_ANQP_FETCH_TRIED))
+ continue;
+ if (os_memcmp(bss->hessid, other->hessid, ETH_ALEN) != 0)
+ continue;
+ if (bss->ssid_len != other->ssid_len ||
+ os_memcmp(bss->ssid, other->ssid, bss->ssid_len) != 0)
+ continue;
+
+ wpa_printf(MSG_DEBUG, "Interworking: Share ANQP data with "
+ "already fetched BSSID " MACSTR " and " MACSTR,
+ MAC2STR(other->bssid), MAC2STR(bss->bssid));
+ other->anqp->users++;
+ return other->anqp;
+ }
+
+ return NULL;
+}
+
+
static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
{
struct wpa_bss *bss;
@@ -1482,6 +1639,17 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
continue; /* AP does not support Interworking */
if (!(bss->flags & WPA_BSS_ANQP_FETCH_TRIED)) {
+ if (bss->anqp == NULL) {
+ bss->anqp = interworking_match_anqp_info(wpa_s,
+ bss);
+ if (bss->anqp) {
+ /* Shared data already fetched */
+ continue;
+ }
+ bss->anqp = wpa_bss_anqp_alloc();
+ if (bss->anqp == NULL)
+ break;
+ }
found++;
bss->flags |= WPA_BSS_ANQP_FETCH_TRIED;
wpa_msg(wpa_s, MSG_INFO, "Starting ANQP fetch for "
@@ -1518,6 +1686,7 @@ int interworking_fetch_anqp(struct wpa_supplicant *wpa_s)
return 0;
wpa_s->network_select = 0;
+ wpa_s->fetch_all_anqp = 1;
interworking_start_fetch_anqp(wpa_s);
@@ -1576,10 +1745,14 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
{
const u8 *pos = data;
struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa);
+ struct wpa_bss_anqp *anqp = NULL;
#ifdef CONFIG_HS20
u8 type;
#endif /* CONFIG_HS20 */
+ if (bss)
+ anqp = bss->anqp;
+
switch (info_id) {
case ANQP_CAPABILITY_LIST:
wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
@@ -1589,9 +1762,9 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
" Venue Name", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Venue Name", pos, slen);
- if (bss) {
- wpabuf_free(bss->anqp_venue_name);
- bss->anqp_venue_name = wpabuf_alloc_copy(pos, slen);
+ if (anqp) {
+ wpabuf_free(anqp->venue_name);
+ anqp->venue_name = wpabuf_alloc_copy(pos, slen);
}
break;
case ANQP_NETWORK_AUTH_TYPE:
@@ -1600,10 +1773,9 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Network Authentication "
"Type", pos, slen);
- if (bss) {
- wpabuf_free(bss->anqp_network_auth_type);
- bss->anqp_network_auth_type =
- wpabuf_alloc_copy(pos, slen);
+ if (anqp) {
+ wpabuf_free(anqp->network_auth_type);
+ anqp->network_auth_type = wpabuf_alloc_copy(pos, slen);
}
break;
case ANQP_ROAMING_CONSORTIUM:
@@ -1611,10 +1783,9 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
" Roaming Consortium list", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Roaming Consortium",
pos, slen);
- if (bss) {
- wpabuf_free(bss->anqp_roaming_consortium);
- bss->anqp_roaming_consortium =
- wpabuf_alloc_copy(pos, slen);
+ if (anqp) {
+ wpabuf_free(anqp->roaming_consortium);
+ anqp->roaming_consortium = wpabuf_alloc_copy(pos, slen);
}
break;
case ANQP_IP_ADDR_TYPE_AVAILABILITY:
@@ -1623,9 +1794,9 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
MAC2STR(sa));
wpa_hexdump(MSG_MSGDUMP, "ANQP: IP Address Availability",
pos, slen);
- if (bss) {
- wpabuf_free(bss->anqp_ip_addr_type_availability);
- bss->anqp_ip_addr_type_availability =
+ if (anqp) {
+ wpabuf_free(anqp->ip_addr_type_availability);
+ anqp->ip_addr_type_availability =
wpabuf_alloc_copy(pos, slen);
}
break;
@@ -1633,9 +1804,9 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
" NAI Realm list", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: NAI Realm", pos, slen);
- if (bss) {
- wpabuf_free(bss->anqp_nai_realm);
- bss->anqp_nai_realm = wpabuf_alloc_copy(pos, slen);
+ if (anqp) {
+ wpabuf_free(anqp->nai_realm);
+ anqp->nai_realm = wpabuf_alloc_copy(pos, slen);
}
break;
case ANQP_3GPP_CELLULAR_NETWORK:
@@ -1643,18 +1814,18 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
" 3GPP Cellular Network information", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: 3GPP Cellular Network",
pos, slen);
- if (bss) {
- wpabuf_free(bss->anqp_3gpp);
- bss->anqp_3gpp = wpabuf_alloc_copy(pos, slen);
+ if (anqp) {
+ wpabuf_free(anqp->anqp_3gpp);
+ anqp->anqp_3gpp = wpabuf_alloc_copy(pos, slen);
}
break;
case ANQP_DOMAIN_NAME:
wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
" Domain Name list", MAC2STR(sa));
wpa_hexdump_ascii(MSG_MSGDUMP, "ANQP: Domain Name", pos, slen);
- if (bss) {
- wpabuf_free(bss->anqp_domain_name);
- bss->anqp_domain_name = wpabuf_alloc_copy(pos, slen);
+ if (anqp) {
+ wpabuf_free(anqp->domain_name);
+ anqp->domain_name = wpabuf_alloc_copy(pos, slen);
}
break;
case ANQP_VENDOR_SPECIFIC:
@@ -1760,6 +1931,7 @@ int interworking_select(struct wpa_supplicant *wpa_s, int auto_select)
wpa_s->network_select = 1;
wpa_s->auto_network_select = 0;
wpa_s->auto_select = !!auto_select;
+ wpa_s->fetch_all_anqp = 0;
wpa_printf(MSG_DEBUG, "Interworking: Start scan for network "
"selection");
wpa_s->scan_res_handler = interworking_scan_res_handler;
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 2c07fd0..0b0ea88 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -586,7 +586,8 @@ fast_reauth=1
# EAP-PSK/PAX/SAKE/GPSK.
# anonymous_identity: Anonymous identity string for EAP (to be used as the
# unencrypted identity with EAP types that support different tunnelled
-# identity, e.g., EAP-TTLS)
+# identity, e.g., EAP-TTLS). This field can also be used with
+# EAP-SIM/AKA/AKA' to store the pseudonym identity.
# password: Password string for EAP. This field can include either the
# plaintext password (using ASCII or hex string) or a NtPasswordHash
# (16-byte MD4 hash of password) in hash:<32 hex digits> format.
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index fb8dba8..6011439 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -578,6 +578,7 @@ struct wpa_supplicant {
unsigned int network_select:1;
unsigned int auto_select:1;
unsigned int auto_network_select:1;
+ unsigned int fetch_all_anqp:1;
#endif /* CONFIG_INTERWORKING */
unsigned int drv_capa_known;
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index fb4fa22..6aa5205 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - Glue code to setup EAPOL and RSN modules
- * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -729,6 +729,44 @@ static void wpa_supplicant_status_cb(void *ctx, const char *status,
wpas_notify_eap_status(wpa_s, status, parameter);
}
+
+
+static void wpa_supplicant_set_anon_id(void *ctx, const u8 *id, size_t len)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ char *str;
+ int res;
+
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP method updated anonymous_identity",
+ id, len);
+
+ if (wpa_s->current_ssid == NULL)
+ return;
+
+ if (id == NULL) {
+ if (wpa_config_set(wpa_s->current_ssid, "anonymous_identity",
+ "NULL", 0) < 0)
+ return;
+ } else {
+ str = os_malloc(len * 2 + 1);
+ if (str == NULL)
+ return;
+ wpa_snprintf_hex(str, len * 2 + 1, id, len);
+ res = wpa_config_set(wpa_s->current_ssid, "anonymous_identity",
+ str, 0);
+ os_free(str);
+ if (res < 0)
+ return;
+ }
+
+ if (wpa_s->conf->update_config) {
+ res = wpa_config_write(wpa_s->confname, wpa_s->conf);
+ if (res) {
+ wpa_printf(MSG_DEBUG, "Failed to update config after "
+ "anonymous_id update");
+ }
+ }
+}
#endif /* IEEE8021X_EAPOL */
@@ -761,6 +799,7 @@ int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s)
ctx->cb = wpa_supplicant_eapol_cb;
ctx->cert_cb = wpa_supplicant_cert_cb;
ctx->status_cb = wpa_supplicant_status_cb;
+ ctx->set_anon_id = wpa_supplicant_set_anon_id;
ctx->cb_ctx = wpa_s;
wpa_s->eapol = eapol_sm_init(ctx);
if (wpa_s->eapol == NULL) {