OSDN Git Service

wpa_supplicant: Update to 07-Sep-2012 TOT
authorDmitry Shmidt <dimitrysh@google.com>
Sun, 9 Sep 2012 22:20:40 +0000 (15:20 -0700)
committerDmitry Shmidt <dimitrysh@google.com>
Mon, 10 Sep 2012 16:26:29 +0000 (09:26 -0700)
commit 44256451130c4766e4a019162de17d0734444ee9
Author: Arik Nemtsov <arik@wizery.com>
Date:   Fri Sep 7 00:22:40 2012 +0300

    AP: Configure basic rates from iface and not conf

Skipped patches:
20ed5e40ba95440a1946cf2dffad3047fb620582
cf8baca6a5719f4f3257631e03317affee015417
a297201df15656dbb0f37e90f3410d9e8102c6fd
620c783753bddd37988269314862dc7e4a62f700

Change-Id: I857aa80af6d1a21b61f7c03a085e7dfc6066d61a
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
40 files changed:
hostapd/Android.mk
hostapd/Makefile
hostapd/hlr_auc_gw.c
hostapd/hlr_auc_gw.txt
hostapd/hostapd.conf
src/ap/hw_features.c
src/ap/wpa_auth.c
src/ap/wpa_auth_ft.c
src/ap/wpa_auth_ie.c
src/common/wpa_common.c
src/common/wpa_common.h
src/drivers/driver_atheros.c
src/eap_peer/eap.c
src/eap_peer/eap.h
src/eap_peer/eap_aka.c
src/eap_peer/eap_config.h
src/eap_peer/eap_sim.c
src/eap_server/eap_i.h
src/eap_server/eap_server_aka.c
src/eap_server/eap_server_sim.c
src/eap_server/eap_sim_db.c
src/eap_server/eap_sim_db.h
src/eapol_supp/eapol_supp_sm.c
src/eapol_supp/eapol_supp_sm.h
src/p2p/p2p_invitation.c
src/rsn_supp/peerkey.c
src/rsn_supp/wpa.c
src/rsn_supp/wpa_ft.c
src/rsn_supp/wpa_ie.c
wpa_supplicant/Android.mk
wpa_supplicant/bss.c
wpa_supplicant/bss.h
wpa_supplicant/ctrl_iface.c
wpa_supplicant/eapol_test.c
wpa_supplicant/events.c
wpa_supplicant/hs20_supplicant.c
wpa_supplicant/interworking.c
wpa_supplicant/wpa_supplicant.conf
wpa_supplicant/wpa_supplicant_i.h
wpa_supplicant/wpas_glue.c

index ed9f654..ee153d0 100644 (file)
@@ -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
index 6809b07..f5dfce0 100644 (file)
@@ -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
index e27ddab..e04e2e9 100644 (file)
@@ -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;
 }
 
index e4b6783..097bbce 100644 (file)
@@ -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:
index 5a2c2ea..edbd772 100644 (file)
@@ -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
index 76aff77..97e1238 100644 (file)
@@ -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)
index 3203d4f..49d8175 100644 (file)
@@ -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(
index 9f7cdae..48bf79b 100644 (file)
@@ -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;
index b88b80a..1786230 100644 (file)
@@ -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) {
index 36febb3..36c308a 100644 (file)
@@ -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;
+}
index c871ae1..603166b 100644 (file)
@@ -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 */
index fefae8c..5f2e675 100644 (file)
@@ -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;
index ba973a5..2ed74b8 100644 (file)
@@ -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);
+}
index cf58608..8bccef1 100644 (file)
@@ -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 */
 
index 1cec4d8..59861cb 100644 (file)
@@ -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;
index a08543e..ed90919 100644 (file)
@@ -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;
 
index fb4ae82..c936a44 100644 (file)
@@ -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;
 }
 
index dfb0ff5..f92704a 100644 (file)
@@ -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;
index 9cd5509..a965cac 100644 (file)
@@ -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);
index 6658d9c..f83c3cb 100644 (file)
@@ -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;
        }
index 68fb1f0..257013e 100644 (file)
@@ -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"
 
 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;
+}
index 1f6375a..53a1a7c 100644 (file)
@@ -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 */
index e3bfa38..851cf49 100644 (file)
@@ -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
 };
 
 
index d2a4b94..c4b87da 100644 (file)
@@ -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);
 };
 
 
index df24c64..d26654b 100644 (file)
@@ -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) {
index 5e4872e..f2bac34 100644 (file)
@@ -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;
index bcd5951..5cf32df 100644 (file)
@@ -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;
        }
index bdf389b..2df060c 100644 (file)
@@ -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;
index 16268d5..6a8f9f1 100644 (file)
@@ -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;
index eae00d8..4f58a92 100644 (file)
@@ -1135,6 +1135,7 @@ SHA1OBJS += src/crypto/sha1-tlsprf.c
 endif
 endif
 
+MD5OBJS =
 ifndef CONFIG_FIPS
 MD5OBJS += src/crypto/md5.c
 endif
index 580a82a..d326bef 100644 (file)
 #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);
index 65e962b..8a307cc 100644 (file)
@@ -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 */
index 4f0c43d..480c077 100644 (file)
@@ -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)
 {
index 7d63c1b..03b8c7e 100644 (file)
@@ -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) {
index c3acad4..bb870c0 100644 (file)
@@ -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;
index 2afa16c..0eb6119 100644 (file)
@@ -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;
index 7b5b20e..b362bcb 100644 (file)
@@ -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;
index 2c07fd0..0b0ea88 100644 (file)
@@ -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.
index fb8dba8..6011439 100644 (file)
@@ -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;
 
index fb4fa22..6aa5205 100644 (file)
@@ -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) {