From a52410c29ff7edd55b10bdf1ec6bae371ddaca2f Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sat, 28 Mar 2015 11:05:13 +0200 Subject: [PATCH] Allow PSK/passphrase to be set only when needed 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 --- src/common/defs.h | 1 + wpa_supplicant/config.c | 1 + wpa_supplicant/config_file.c | 8 ++++- wpa_supplicant/config_ssid.h | 8 +++++ wpa_supplicant/events.c | 24 +++++++++++-- wpa_supplicant/wpa_supplicant.c | 28 +++++++++++++-- wpa_supplicant/wpa_supplicant.conf | 5 +++ wpa_supplicant/wpas_glue.c | 58 ++++++++++++++++++------------ wpa_supplicant/wpas_glue.h | 3 ++ 9 files changed, 109 insertions(+), 27 deletions(-) diff --git a/src/common/defs.h b/src/common/defs.h index b5f4f801e..24f80ad4a 100644 --- a/src/common/defs.h +++ b/src/common/defs.h @@ -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 }; diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index a01a9109e..c69054222 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -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) }, diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index 3d3a6e404..781f5e5a9 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -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); diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h index 7c826cfd9..23a37cc35 100644 --- a/wpa_supplicant/config_ssid.h +++ b/wpa_supplicant/config_ssid.h @@ -180,6 +180,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_* */ diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index b10f583cd..b0671bfed 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -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; } diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 6f5fbadaa..f690b9190 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -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; diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf index 8964b3f72..853b156a7 100644 --- a/wpa_supplicant/wpa_supplicant.conf +++ b/wpa_supplicant/wpa_supplicant.conf @@ -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 diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c index 1bb82ba71..48a5d6987 100644 --- a/wpa_supplicant/wpas_glue.c +++ b/wpa_supplicant/wpas_glue.c @@ -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 diff --git a/wpa_supplicant/wpas_glue.h b/wpa_supplicant/wpas_glue.h index 9808c2265..5585e5615 100644 --- a/wpa_supplicant/wpas_glue.h +++ b/wpa_supplicant/wpas_glue.h @@ -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 */