]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
EXT PW: Add framework for supporting external password storage
authorJouni Malinen <j@w1.fi>
Fri, 3 Aug 2012 18:28:42 +0000 (21:28 +0300)
committerJouni Malinen <j@w1.fi>
Fri, 3 Aug 2012 19:15:42 +0000 (22:15 +0300)
This new mechanism can be used to make wpa_supplicant using external
storage (e.g., key store in the operating system) for passwords,
passphrases, and PSKs. This commit is only adding the framework part
needed to support this, i.e., no actual configuration parameter can
yet use this new mechanism. In addition, only a simple test backend
is added to allow developer testing of the functionality.

Signed-hostap: Jouni Malinen <j@w1.fi>

15 files changed:
src/utils/ext_password.c [new file with mode: 0644]
src/utils/ext_password.h [new file with mode: 0644]
src/utils/ext_password_i.h [new file with mode: 0644]
src/utils/ext_password_test.c [new file with mode: 0644]
wpa_supplicant/Android.mk
wpa_supplicant/Makefile
wpa_supplicant/config.c
wpa_supplicant/config.h
wpa_supplicant/config_file.c
wpa_supplicant/config_ssid.h
wpa_supplicant/defconfig
wpa_supplicant/eapol_test.c
wpa_supplicant/wpa_supplicant.c
wpa_supplicant/wpa_supplicant.conf
wpa_supplicant/wpa_supplicant_i.h

diff --git a/src/utils/ext_password.c b/src/utils/ext_password.c
new file mode 100644 (file)
index 0000000..0613119
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * External password backend
+ * Copyright (c) 2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#ifdef __linux__
+#include <sys/mman.h>
+#endif /* __linux__ */
+
+#include "common.h"
+#include "ext_password_i.h"
+
+
+#ifdef CONFIG_EXT_PASSWORD_TEST
+extern struct ext_password_backend ext_password_test;
+#endif /* CONFIG_EXT_PASSWORD_TEST */
+
+static const struct ext_password_backend *backends[] = {
+#ifdef CONFIG_EXT_PASSWORD_TEST
+       &ext_password_test,
+#endif /* CONFIG_EXT_PASSWORD_TEST */
+       NULL
+};
+
+struct ext_password_data {
+       const struct ext_password_backend *backend;
+       void *priv;
+};
+
+
+struct ext_password_data * ext_password_init(const char *backend,
+                                            const char *params)
+{
+       struct ext_password_data *data;
+       int i;
+
+       data = os_zalloc(sizeof(*data));
+       if (data == NULL)
+               return NULL;
+
+       for (i = 0; backends[i]; i++) {
+               if (os_strcmp(backends[i]->name, backend) == 0) {
+                       data->backend = backends[i];
+                       break;
+               }
+       }
+
+       if (!data->backend) {
+               os_free(data);
+               return NULL;
+       }
+
+       data->priv = data->backend->init(params);
+       if (data->priv == NULL) {
+               os_free(data);
+               return NULL;
+       }
+
+       return data;
+}
+
+
+void ext_password_deinit(struct ext_password_data *data)
+{
+       if (data && data->backend && data->priv)
+               data->backend->deinit(data->priv);
+       os_free(data);
+}
+
+
+struct wpabuf * ext_password_get(struct ext_password_data *data,
+                                const char *name)
+{
+       if (data == NULL)
+               return NULL;
+       return data->backend->get(data->priv, name);
+}
+
+
+struct wpabuf * ext_password_alloc(size_t len)
+{
+       struct wpabuf *buf;
+
+       buf = wpabuf_alloc(len);
+       if (buf == NULL)
+               return NULL;
+
+#ifdef __linux__
+       if (mlock(wpabuf_head(buf), wpabuf_len(buf)) < 0) {
+               wpa_printf(MSG_ERROR, "EXT PW: mlock failed: %s",
+                          strerror(errno));
+       }
+#endif /* __linux__ */
+
+       return buf;
+}
+
+
+void ext_password_free(struct wpabuf *pw)
+{
+       if (pw == NULL)
+               return;
+       os_memset(wpabuf_mhead(pw), 0, wpabuf_len(pw));
+#ifdef __linux__
+       if (munlock(wpabuf_head(pw), wpabuf_len(pw)) < 0) {
+               wpa_printf(MSG_ERROR, "EXT PW: munlock failed: %s",
+                          strerror(errno));
+       }
+#endif /* __linux__ */
+       wpabuf_free(pw);
+}
diff --git a/src/utils/ext_password.h b/src/utils/ext_password.h
new file mode 100644 (file)
index 0000000..e3e46ea
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * External password backend
+ * Copyright (c) 2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EXT_PASSWORD_H
+#define EXT_PASSWORD_H
+
+struct ext_password_data;
+
+#ifdef CONFIG_EXT_PASSWORD
+
+struct ext_password_data * ext_password_init(const char *backend,
+                                            const char *params);
+void ext_password_deinit(struct ext_password_data *data);
+
+struct wpabuf * ext_password_get(struct ext_password_data *data,
+                                const char *name);
+void ext_password_free(struct wpabuf *pw);
+
+#else /* CONFIG_EXT_PASSWORD */
+
+#define ext_password_init(b, p) ((void *) 1)
+#define ext_password_deinit(d) do { } while (0)
+#define ext_password_get(d, n) (NULL)
+#define ext_password_free(p) do { } while (0)
+
+#endif /* CONFIG_EXT_PASSWORD */
+
+#endif /* EXT_PASSWORD_H */
diff --git a/src/utils/ext_password_i.h b/src/utils/ext_password_i.h
new file mode 100644 (file)
index 0000000..043e731
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * External password backend - internal definitions
+ * Copyright (c) 2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EXT_PASSWORD_I_H
+#define EXT_PASSWORD_I_H
+
+#include "ext_password.h"
+
+struct ext_password_backend {
+       const char *name;
+       void * (*init)(const char *params);
+       void (*deinit)(void *ctx);
+       struct wpabuf * (*get)(void *ctx, const char *name);
+};
+
+struct wpabuf * ext_password_alloc(size_t len);
+
+#endif /* EXT_PASSWORD_I_H */
diff --git a/src/utils/ext_password_test.c b/src/utils/ext_password_test.c
new file mode 100644 (file)
index 0000000..3801bb8
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * External password backend
+ * Copyright (c) 2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "ext_password_i.h"
+
+
+struct ext_password_test_data {
+       char *params;
+};
+
+
+static void * ext_password_test_init(const char *params)
+{
+       struct ext_password_test_data *data;
+
+       data = os_zalloc(sizeof(*data));
+       if (data == NULL)
+               return NULL;
+
+       if (params)
+               data->params = os_strdup(params);
+
+       return data;
+}
+
+
+static void ext_password_test_deinit(void *ctx)
+{
+       struct ext_password_test_data *data = ctx;
+
+       os_free(data->params);
+       os_free(data);
+}
+
+
+static struct wpabuf * ext_password_test_get(void *ctx, const char *name)
+{
+       struct ext_password_test_data *data = ctx;
+       char *pos, *pos2;
+       size_t nlen;
+
+       wpa_printf(MSG_DEBUG, "EXT PW TEST: get(%s)", name);
+
+       pos = data->params;
+       if (pos == NULL)
+               return NULL;
+       nlen = os_strlen(name);
+
+       while (pos && *pos) {
+               if (os_strncmp(pos, name, nlen) == 0 && pos[nlen] == '=') {
+                       struct wpabuf *buf;
+                       pos += nlen + 1;
+                       pos2 = pos;
+                       while (*pos2 != '|' && *pos2 != '\0')
+                               pos2++;
+                       buf = ext_password_alloc(pos2 - pos);
+                       if (buf == NULL)
+                               return NULL;
+                       wpabuf_put_data(buf, pos, pos2 - pos);
+                       wpa_hexdump_ascii_key(MSG_DEBUG, "EXT PW TEST: value",
+                                             wpabuf_head(buf),
+                                             wpabuf_len(buf));
+                       return buf;
+               }
+
+               pos = os_strchr(pos + 1, '|');
+               if (pos)
+                       pos++;
+       }
+
+       wpa_printf(MSG_DEBUG, "EXT PW TEST: get(%s) - not found", name);
+
+       return NULL;
+}
+
+
+const struct ext_password_backend ext_password_test = {
+       .name = "test",
+       .init = ext_password_test_init,
+       .deinit = ext_password_test_deinit,
+       .get = ext_password_test_get,
+};
index 0666f4d1e8cedc67a0453ef42dc26bfc1eae27c2..27dda29d293ccba224276114fbac5235d63ef167 100644 (file)
@@ -1321,6 +1321,17 @@ L_CFLAGS += -DCONFIG_AUTOSCAN
 OBJS += autoscan.c
 endif
 
+ifdef CONFIG_EXT_PASSWORD_TEST
+OBJS += ../src/utils/ext_password_test.c
+L_CFLAGS += -DCONFIG_EXT_PASSWORD_TEST
+NEED_EXT_PASSWORD=y
+endif
+
+ifdef NEED_EXT_PASSWORD
+OBJS += ../src/utils/ext_password.c
+L_CFLAGS += -DCONFIG_EXT_PASSWORD
+endif
+
 ifdef NEED_GAS
 OBJS += ../src/common/gas.c
 OBJS += gas_query.c
index e8fe6f21f71612191ee825adabee679aadb9d2f0..a7683dd2683e182c24d8e5db6cdfc95e0370253d 100644 (file)
@@ -1346,6 +1346,17 @@ CFLAGS += -DCONFIG_AUTOSCAN
 OBJS += autoscan.o
 endif
 
+ifdef CONFIG_EXT_PASSWORD_TEST
+OBJS += ../src/utils/ext_password_test.o
+CFLAGS += -DCONFIG_EXT_PASSWORD_TEST
+NEED_EXT_PASSWORD=y
+endif
+
+ifdef NEED_EXT_PASSWORD
+OBJS += ../src/utils/ext_password.o
+CFLAGS += -DCONFIG_EXT_PASSWORD
+endif
+
 ifdef NEED_GAS
 OBJS += ../src/common/gas.o
 OBJS += gas_query.o
index 54a767e10da00e59c294e267e0bee284d59f659d..9d7f38ed11c8396b341b421fb131780457941401 100644 (file)
@@ -1866,6 +1866,7 @@ void wpa_config_free(struct wpa_config *config)
        wpabuf_free(config->wps_nfc_dh_pubkey);
        wpabuf_free(config->wps_nfc_dh_privkey);
        wpabuf_free(config->wps_nfc_dev_pw);
+       os_free(config->ext_password_backend);
        os_free(config);
 }
 
@@ -2968,7 +2969,8 @@ static const struct global_parse_data global_fields[] = {
        { INT_RANGE(wps_nfc_dev_pw_id, 0x10, 0xffff), 0 },
        { BIN(wps_nfc_dh_pubkey), 0 },
        { BIN(wps_nfc_dh_privkey), 0 },
-       { BIN(wps_nfc_dev_pw), 0 }
+       { BIN(wps_nfc_dev_pw), 0 },
+       { STR(ext_password_backend), CFG_CHANGED_EXT_PW_BACKEND }
 };
 
 #undef FUNC
index 6f4f8018297a7f4ebef65fafe3c6dec3adf0b5f5..c8c154251053941168c8a28fb21af4b5269f55e1 100644 (file)
@@ -206,6 +206,7 @@ struct wpa_cred {
 #define CFG_CHANGED_P2P_LISTEN_CHANNEL BIT(11)
 #define CFG_CHANGED_P2P_OPER_CHANNEL BIT(12)
 #define CFG_CHANGED_P2P_PREF_CHAN BIT(13)
+#define CFG_CHANGED_EXT_PW_BACKEND BIT(14)
 
 /**
  * struct wpa_config - wpa_supplicant configuration data
@@ -710,6 +711,13 @@ struct wpa_config {
         * wps_nfc_dh_pubkey - NFC Device Password for password token
         */
        struct wpabuf *wps_nfc_dev_pw;
+
+       /**
+        * ext_password_backend - External password backend or %NULL if none
+        *
+        * format: <backend name>[:<optional backend parameters>]
+        */
+       char *ext_password_backend;
 };
 
 
index a55a5c966e1df3141a71d606cb471a9442b3e7f6..0520646b49a959854be22e5d56bc756391c249b3 100644 (file)
@@ -869,6 +869,10 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
        write_global_bin(f, "wps_nfc_dh_pubkey", config->wps_nfc_dh_pubkey);
        write_global_bin(f, "wps_nfc_dh_privkey", config->wps_nfc_dh_privkey);
        write_global_bin(f, "wps_nfc_dev_pw", config->wps_nfc_dev_pw);
+
+       if (config->ext_password_backend)
+               fprintf(f, "ext_password_backend=%s\n",
+                       config->ext_password_backend);
 }
 
 #endif /* CONFIG_NO_CONFIG_WRITE */
index c35f7c3fe08356dc7c06608f9fd40d4896541da0..f4d551df08b0c077f13419631889d45547df3a25 100644 (file)
@@ -140,6 +140,14 @@ struct wpa_ssid {
         */
        char *passphrase;
 
+       /**
+        * ext_psk - PSK/passphrase name in external storage
+        *
+        * If this is set, PSK/passphrase will be fetched from external storage
+        * when requesting association with the network.
+        */
+       char *ext_psk;
+
        /**
         * pairwise_cipher - Bitfield of allowed pairwise ciphers, WPA_CIPHER_*
         */
index 849f2448fda68372e040487b2c0245460108ae05..e2b6cbe4227f7a544f5140d0c893e1fef6396991 100644 (file)
@@ -512,3 +512,11 @@ CONFIG_PEERKEY=y
 #CONFIG_AUTOSCAN_EXPONENTIAL=y
 # For periodic module:
 #CONFIG_AUTOSCAN_PERIODIC=y
+
+# Password (and passphrase, etc.) backend for external storage
+# These optional mechanisms can be used to add support for storing passwords
+# and other secrets in external (to wpa_supplicant) location. This allows, for
+# example, operating system specific key storage to be used
+#
+# External password backend for testing purposes (developer use)
+#CONFIG_EXT_PASSWORD_TEST=y
index e53e15634dfa1da0e421ed9d85c232549745d526..825e2b9dbf6f62cd1c7b4192b0c4cba8b540a2c4 100644 (file)
@@ -13,6 +13,7 @@
 #include <assert.h>
 
 #include "common.h"
+#include "utils/ext_password.h"
 #include "config.h"
 #include "eapol_supp/eapol_supp_sm.h"
 #include "eap_peer/eap.h"
@@ -506,6 +507,10 @@ static void test_eapol_clean(struct eapol_test_data *e,
                wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
                wpa_s->ctrl_iface = NULL;
        }
+
+       ext_password_deinit(wpa_s->ext_pw);
+       wpa_s->ext_pw = NULL;
+
        wpa_config_free(wpa_s->conf);
 
        p = e->extra_attrs;
@@ -1228,6 +1233,9 @@ int main(int argc, char *argv[])
        if (test_eapol(&eapol_test, &wpa_s, wpa_s.conf->ssid))
                return -1;
 
+       if (wpas_init_ext_pw(&wpa_s) < 0)
+               return -1;
+
        if (wait_for_monitor)
                wpa_supplicant_ctrl_iface_wait(wpa_s.ctrl_iface);
 
index 502541014df7cb01bb567f53c51dc216dcdf6263..9247195479b8c501866dabb9744ccd37bd5f0fda 100644 (file)
@@ -21,6 +21,7 @@
 #include "rsn_supp/wpa.h"
 #include "eloop.h"
 #include "config.h"
+#include "utils/ext_password.h"
 #include "l2_packet/l2_packet.h"
 #include "wpa_supplicant_i.h"
 #include "driver_i.h"
@@ -453,6 +454,9 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
        wpa_s->bssid_filter = NULL;
 
        wnm_bss_keep_alive_deinit(wpa_s);
+
+       ext_password_deinit(wpa_s->ext_pw);
+       wpa_s->ext_pw = NULL;
 }
 
 
@@ -2500,6 +2504,38 @@ static int pcsc_reader_init(struct wpa_supplicant *wpa_s)
 }
 
 
+int wpas_init_ext_pw(struct wpa_supplicant *wpa_s)
+{
+       char *val, *pos;
+
+       ext_password_deinit(wpa_s->ext_pw);
+       wpa_s->ext_pw = NULL;
+       eapol_sm_set_ext_pw_ctx(wpa_s->eapol, NULL);
+
+       if (!wpa_s->conf->ext_password_backend)
+               return 0;
+
+       val = os_strdup(wpa_s->conf->ext_password_backend);
+       if (val == NULL)
+               return -1;
+       pos = os_strchr(val, ':');
+       if (pos)
+               *pos++ = '\0';
+
+       wpa_printf(MSG_DEBUG, "EXT PW: Initialize backend '%s'", val);
+
+       wpa_s->ext_pw = ext_password_init(val, pos);
+       os_free(val);
+       if (wpa_s->ext_pw == NULL) {
+               wpa_printf(MSG_DEBUG, "EXT PW: Failed to initialize backend");
+               return -1;
+       }
+       eapol_sm_set_ext_pw_ctx(wpa_s->eapol, wpa_s->ext_pw);
+
+       return 0;
+}
+
+
 static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
                                     struct wpa_interface *iface)
 {
@@ -2725,6 +2761,9 @@ next_driver:
        if (pcsc_reader_init(wpa_s) < 0)
                return -1;
 
+       if (wpas_init_ext_pw(wpa_s) < 0)
+               return -1;
+
        return 0;
 }
 
@@ -3153,6 +3192,9 @@ void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s)
                }
        }
 
+       if (wpa_s->conf->changed_parameters & CFG_CHANGED_EXT_PW_BACKEND)
+               wpas_init_ext_pw(wpa_s);
+
 #ifdef CONFIG_WPS
        wpas_wps_update_config(wpa_s);
 #endif /* CONFIG_WPS */
index af0da2065a20670a944dee20ae176b08ecc085b4..05a2d0bc2d89373448031723af81d6008312654f 100644 (file)
@@ -255,6 +255,10 @@ fast_reauth=1
 # 1 = only include configured SSIDs in scan results/BSS table
 #filter_ssids=0
 
+# Password (and passphrase, etc.) backend for external storage
+# format: <backend name>[:<optional backend parameters>]
+#ext_password_backend=test:pw1=password|pw2=testing
+
 
 # Interworking (IEEE 802.11u)
 
index b608f29872e4fa486b7b7835550273360b7dc454..d6d94105605cb7d43518662a9aef47545eea3873 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * wpa_supplicant - Internal definitions
- * Copyright (c) 2003-2010, 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.
@@ -574,6 +574,8 @@ struct wpa_supplicant {
 
        /* WLAN_REASON_* reason codes. Negative if locally generated. */
        int disconnect_reason;
+
+       struct ext_password_data *ext_pw;
 };
 
 
@@ -697,4 +699,6 @@ static inline int network_is_persistent_group(struct wpa_ssid *ssid)
 
 int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
 
+int wpas_init_ext_pw(struct wpa_supplicant *wpa_s);
+
 #endif /* WPA_SUPPLICANT_I_H */