Allow PSK/passphrase to be set only when needed
authorJouni Malinen <j@w1.fi>
Sat, 28 Mar 2015 09:05:13 +0000 (11:05 +0200)
committerJouni Malinen <j@w1.fi>
Sat, 28 Mar 2015 09:05:13 +0000 (11:05 +0200)
The new network profile parameter mem_only_psk=1 can be used to specify
that the PSK/passphrase for that network is requested over the control
interface (ctrl_iface or D-Bus) similarly to the EAP network parameter
requests. The PSK/passphrase can then be configured temporarily in a way
that prevents it from getting stored to the configuration file.

For example:

Event:
CTRL-REQ-PSK_PASSPHRASE-0:PSK or passphrase needed for SSID test-wpa2-psk

Response:
CTRL-RSP-PSK_PASSPHRASE-0:"qwertyuiop"

Note: The response value uses the same encoding as the psk network
profile parameter, i.e., passphrase is within double quotation marks.

Signed-off-by: Jouni Malinen <j@w1.fi>
src/common/defs.h
wpa_supplicant/config.c
wpa_supplicant/config_file.c
wpa_supplicant/config_ssid.h
wpa_supplicant/events.c
wpa_supplicant/wpa_supplicant.c
wpa_supplicant/wpa_supplicant.conf
wpa_supplicant/wpas_glue.c
wpa_supplicant/wpas_glue.h

index b5f4f80..24f80ad 100644 (file)
@@ -310,6 +310,7 @@ enum wpa_ctrl_req_type {
        WPA_CTRL_REQ_EAP_OTP,
        WPA_CTRL_REQ_EAP_PASSPHRASE,
        WPA_CTRL_REQ_SIM,
+       WPA_CTRL_REQ_PSK_PASSPHRASE,
        NUM_WPA_CTRL_REQS
 };
 
index a01a910..c690542 100644 (file)
@@ -1816,6 +1816,7 @@ static const struct parse_data ssid_fields[] = {
        { FUNC(bssid_blacklist) },
        { FUNC(bssid_whitelist) },
        { FUNC_KEY(psk) },
+       { INT(mem_only_psk) },
        { FUNC(proto) },
        { FUNC(key_mgmt) },
        { INT(bg_scan_period) },
index 3d3a6e4..781f5e5 100644 (file)
@@ -501,7 +501,12 @@ static void write_bssid(FILE *f, struct wpa_ssid *ssid)
 
 static void write_psk(FILE *f, struct wpa_ssid *ssid)
 {
-       char *value = wpa_config_get(ssid, "psk");
+       char *value;
+
+       if (ssid->mem_only_psk)
+               return;
+
+       value = wpa_config_get(ssid, "psk");
        if (value == NULL)
                return;
        fprintf(f, "\tpsk=%s\n", value);
@@ -673,6 +678,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
        write_str(f, "bssid_blacklist", ssid);
        write_str(f, "bssid_whitelist", ssid);
        write_psk(f, ssid);
+       INT(mem_only_psk);
        write_proto(f, ssid);
        write_key_mgmt(f, ssid);
        INT_DEF(bg_scan_period, DEFAULT_BG_SCAN_PERIOD);
index 7c826cf..23a37cc 100644 (file)
@@ -181,6 +181,14 @@ struct wpa_ssid {
        char *ext_psk;
 
        /**
+        * mem_only_psk - Whether to keep PSK/passphrase only in memory
+        *
+        * 0 = allow psk/passphrase to be stored to the configuration file
+        * 1 = do not store psk/passphrase to the configuration file
+        */
+       int mem_only_psk;
+
+       /**
         * pairwise_cipher - Bitfield of allowed pairwise ciphers, WPA_CIPHER_*
         */
        int pairwise_cipher;
index b10f583..b0671bf 100644 (file)
@@ -1085,14 +1085,13 @@ struct wpa_bss * wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s,
        struct wpa_bss *selected = NULL;
        int prio;
        struct wpa_ssid *next_ssid = NULL;
+       struct wpa_ssid *ssid;
 
        if (wpa_s->last_scan_res == NULL ||
            wpa_s->last_scan_res_used == 0)
                return NULL; /* no scan results from last update */
 
        if (wpa_s->next_ssid) {
-               struct wpa_ssid *ssid;
-
                /* check that next_ssid is still valid */
                for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
                        if (ssid == wpa_s->next_ssid)
@@ -1128,6 +1127,27 @@ struct wpa_bss * wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s,
                        break;
        }
 
+       ssid = *selected_ssid;
+       if (selected && ssid && ssid->mem_only_psk && !ssid->psk_set &&
+           !ssid->passphrase && !ssid->ext_psk) {
+               const char *field_name, *txt = NULL;
+
+               wpa_dbg(wpa_s, MSG_DEBUG,
+                       "PSK/passphrase not yet available for the selected network");
+
+               wpas_notify_network_request(wpa_s, ssid,
+                                           WPA_CTRL_REQ_PSK_PASSPHRASE, NULL);
+
+               field_name = wpa_supplicant_ctrl_req_to_string(
+                       WPA_CTRL_REQ_PSK_PASSPHRASE, NULL, &txt);
+               if (field_name == NULL)
+                       return NULL;
+
+               wpas_send_ctrl_req(wpa_s, ssid, field_name, txt);
+
+               selected = NULL;
+       }
+
        return selected;
 }
 
index 6f5fbad..f690b91 100644 (file)
@@ -1239,7 +1239,12 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
        }
 
        if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) {
-               wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN, NULL);
+               int psk_set = 0;
+
+               if (ssid->psk_set) {
+                       wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN, NULL);
+                       psk_set = 1;
+               }
 #ifndef CONFIG_NO_PBKDF2
                if (bss && ssid->bssid_set && ssid->ssid_len == 0 &&
                    ssid->passphrase) {
@@ -1249,6 +1254,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                        wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
                                        psk, PMK_LEN);
                        wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL);
+                       psk_set = 1;
                        os_memset(psk, 0, sizeof(psk));
                }
 #endif /* CONFIG_NO_PBKDF2 */
@@ -1286,6 +1292,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                                                "external passphrase)",
                                                psk, PMK_LEN);
                                wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL);
+                               psk_set = 1;
                                os_memset(psk, 0, sizeof(psk));
                        } else
 #endif /* CONFIG_NO_PBKDF2 */
@@ -1298,6 +1305,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                                        return -1;
                                }
                                wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL);
+                               psk_set = 1;
                                os_memset(psk, 0, sizeof(psk));
                        } else {
                                wpa_msg(wpa_s, MSG_INFO, "EXT PW: No suitable "
@@ -1311,6 +1319,12 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                        ext_password_free(pw);
                }
 #endif /* CONFIG_EXT_PASSWORD */
+
+               if (!psk_set) {
+                       wpa_msg(wpa_s, MSG_INFO,
+                               "No PSK available for association");
+                       return -1;
+               }
        } else
                wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
 
@@ -4967,6 +4981,15 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
                str_clear_free(eap->external_sim_resp);
                eap->external_sim_resp = os_strdup(value);
                break;
+       case WPA_CTRL_REQ_PSK_PASSPHRASE:
+               if (wpa_config_set(ssid, "psk", value, 0) < 0)
+                       return -1;
+               ssid->mem_only_psk = 1;
+               if (ssid->passphrase)
+                       wpa_config_update_psk(ssid);
+               if (wpa_s->wpa_state == WPA_SCANNING && !wpa_s->scanning)
+                       wpa_supplicant_req_scan(wpa_s, 0, 0);
+               break;
        default:
                wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", field);
                return -1;
@@ -5014,7 +5037,8 @@ int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
        }
 
        if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set &&
-           (!ssid->passphrase || ssid->ssid_len != 0) && !ssid->ext_psk)
+           (!ssid->passphrase || ssid->ssid_len != 0) && !ssid->ext_psk &&
+           !ssid->mem_only_psk)
                return 1;
 
        return 0;
index 8964b3f..853b156 100644 (file)
@@ -740,6 +740,11 @@ fast_reauth=1
 # startup and reconfiguration time can be optimized by generating the PSK only
 # only when the passphrase or SSID has actually changed.
 #
+# mem_only_psk: Whether to keep PSK/passphrase only in memory
+# 0 = allow psk/passphrase to be stored to the configuration file
+# 1 = do not store psk/passphrase to the configuration file
+#mem_only_psk=0
+#
 # eapol_flags: IEEE 802.1X/EAPOL options (bit field)
 # Dynamic WEP key required for non-WPA mode
 # bit0 (1): require dynamically generated unicast WEP key
index 1bb82ba..48a5d69 100644 (file)
@@ -737,6 +737,8 @@ enum wpa_ctrl_req_type wpa_supplicant_ctrl_req_from_string(const char *field)
                return WPA_CTRL_REQ_EAP_PASSPHRASE;
        else if (os_strcmp(field, "SIM") == 0)
                return WPA_CTRL_REQ_SIM;
+       else if (os_strcmp(field, "PSK_PASSPHRASE") == 0)
+               return WPA_CTRL_REQ_PSK_PASSPHRASE;
        return WPA_CTRL_REQ_UNKNOWN;
 }
 
@@ -776,6 +778,10 @@ const char * wpa_supplicant_ctrl_req_to_string(enum wpa_ctrl_req_type field,
        case WPA_CTRL_REQ_SIM:
                ret = "SIM";
                break;
+       case WPA_CTRL_REQ_PSK_PASSPHRASE:
+               *txt = "PSK or passphrase";
+               ret = "PSK_PASSPHRASE";
+               break;
        default:
                break;
        }
@@ -789,6 +795,35 @@ const char * wpa_supplicant_ctrl_req_to_string(enum wpa_ctrl_req_type field,
        return ret;
 }
 
+
+void wpas_send_ctrl_req(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+                       const char *field_name, const char *txt)
+{
+       char *buf;
+       size_t buflen;
+       int len;
+
+       buflen = 100 + os_strlen(txt) + ssid->ssid_len;
+       buf = os_malloc(buflen);
+       if (buf == NULL)
+               return;
+       len = os_snprintf(buf, buflen, "%s-%d:%s needed for SSID ",
+                         field_name, ssid->id, txt);
+       if (os_snprintf_error(buflen, len)) {
+               os_free(buf);
+               return;
+       }
+       if (ssid->ssid && buflen > len + ssid->ssid_len) {
+               os_memcpy(buf + len, ssid->ssid, ssid->ssid_len);
+               len += ssid->ssid_len;
+               buf[len] = '\0';
+       }
+       buf[buflen - 1] = '\0';
+       wpa_msg(wpa_s, MSG_INFO, WPA_CTRL_REQ "%s", buf);
+       os_free(buf);
+}
+
+
 #ifdef IEEE8021X_EAPOL
 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
 static void wpa_supplicant_eap_param_needed(void *ctx,
@@ -798,9 +833,6 @@ static void wpa_supplicant_eap_param_needed(void *ctx,
        struct wpa_supplicant *wpa_s = ctx;
        struct wpa_ssid *ssid = wpa_s->current_ssid;
        const char *field_name, *txt = NULL;
-       char *buf;
-       size_t buflen;
-       int len;
 
        if (ssid == NULL)
                return;
@@ -817,25 +849,7 @@ static void wpa_supplicant_eap_param_needed(void *ctx,
 
        wpas_notify_eap_status(wpa_s, "eap parameter needed", field_name);
 
-       buflen = 100 + os_strlen(txt) + ssid->ssid_len;
-       buf = os_malloc(buflen);
-       if (buf == NULL)
-               return;
-       len = os_snprintf(buf, buflen,
-                         WPA_CTRL_REQ "%s-%d:%s needed for SSID ",
-                         field_name, ssid->id, txt);
-       if (os_snprintf_error(buflen, len)) {
-               os_free(buf);
-               return;
-       }
-       if (ssid->ssid && buflen > len + ssid->ssid_len) {
-               os_memcpy(buf + len, ssid->ssid, ssid->ssid_len);
-               len += ssid->ssid_len;
-               buf[len] = '\0';
-       }
-       buf[buflen - 1] = '\0';
-       wpa_msg(wpa_s, MSG_INFO, "%s", buf);
-       os_free(buf);
+       wpas_send_ctrl_req(wpa_s, ssid, field_name, txt);
 }
 #else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
 #define wpa_supplicant_eap_param_needed NULL
index 9808c22..5585e56 100644 (file)
@@ -22,4 +22,7 @@ const char * wpa_supplicant_ctrl_req_to_string(enum wpa_ctrl_req_type field,
 
 enum wpa_ctrl_req_type wpa_supplicant_ctrl_req_from_string(const char *field);
 
+void wpas_send_ctrl_req(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+                       const char *field_name, const char *txt);
+
 #endif /* WPAS_GLUE_H */