Re: [patch] WPS: support up to 4 WEP keys when parsing received credentials
Andriy Tkachuk <andriy.v.tkachuk <at> globallogic.com>
2009-07-02 14:44:38 GMT
Addition to prev. patch - changes in wps_hostapd.c to compile hostapd also.
Regards,
Andriy
On 2009-07-02 16:46, Andriy Tkachuk wrote:
> Hi to all.
>
> Attached is the patch which makes Enrollee correctly parse multiple
> network keys in received credentials. This may be needed when
> Registrar sends several WEP keys (for example, Linksys WAP610N do this).
>
> Regards,
> Andriy
> ------------------------------------------------------------------------
>
> _______________________________________________
> HostAP mailing list
> HostAP <at> lists.shmoo.com
> http://lists.shmoo.com/mailman/listinfo/hostap
diff --git a/hostapd/wps_hostapd.c b/hostapd/wps_hostapd.c
index a0c1e3a..ea0dee8 100644
--- a/hostapd/wps_hostapd.c
+++ b/hostapd/wps_hostapd.c
<at> <at> -214,9 +214,9 <at> <at> static int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred)
wpa_printf(MSG_DEBUG, "WPS: Authentication Type 0x%x",
cred->auth_type);
wpa_printf(MSG_DEBUG, "WPS: Encryption Type 0x%x", cred->encr_type);
- wpa_printf(MSG_DEBUG, "WPS: Network Key Index %d", cred->key_idx);
+ wpa_printf(MSG_DEBUG, "WPS: Network Keys %d", cred->keys_num);
wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key",
- cred->key, cred->key_len);
+ cred->key[0], cred->key_len[0]);
wpa_printf(MSG_DEBUG, "WPS: MAC Address " MACSTR,
MAC2STR(cred->mac_addr));
<at> <at> -241,21 +241,21 <at> <at> static int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred)
hapd->wps->ssid_len = cred->ssid_len;
hapd->wps->encr_types = cred->encr_type;
hapd->wps->auth_types = cred->auth_type;
- if (cred->key == NULL) {
+ if (cred->key[0] == NULL) {
os_free(hapd->wps->network_key);
hapd->wps->network_key = NULL;
hapd->wps->network_key_len = 0;
} else {
if (hapd->wps->network_key == NULL ||
- hapd->wps->network_key_len < cred->key_len) {
+ hapd->wps->network_key_len < cred->key_len[0]) {
hapd->wps->network_key_len = 0;
os_free(hapd->wps->network_key);
- hapd->wps->network_key = os_malloc(cred->key_len);
+ hapd->wps->network_key = os_malloc(cred->key_len[0]);
if (hapd->wps->network_key == NULL)
return -1;
}
- hapd->wps->network_key_len = cred->key_len;
- os_memcpy(hapd->wps->network_key, cred->key, cred->key_len);
+ hapd->wps->network_key_len = cred->key_len[0];
+ os_memcpy(hapd->wps->network_key, cred->key[0], cred->key_len[0]);
}
hapd->wps->wps_state = WPS_STATE_CONFIGURED;
<at> <at> -326,20 +326,20 <at> <at> static int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred)
}
fprintf(nconf, "\n");
- if (cred->key_len >= 8 && cred->key_len < 64) {
+ if (cred->key_len[0] >= 8 && cred->key_len[0] < 64) {
fprintf(nconf, "wpa_passphrase=");
- for (i = 0; i < cred->key_len; i++)
- fputc(cred->key[i], nconf);
+ for (i = 0; i < cred->key_len[0]; i++)
+ fputc(cred->key[0][i], nconf);
fprintf(nconf, "\n");
- } else if (cred->key_len == 64) {
+ } else if (cred->key_len[0] == 64) {
fprintf(nconf, "wpa_psk=");
- for (i = 0; i < cred->key_len; i++)
- fputc(cred->key[i], nconf);
+ for (i = 0; i < cred->key_len[0]; i++)
+ fputc(cred->key[0][i], nconf);
fprintf(nconf, "\n");
} else {
- wpa_printf(MSG_WARNING, "WPS: Invalid key length %lu "
+ wpa_printf(MSG_WARNING, "WPS: Invalid key[0] length %lu "
"for WPA/WPA2",
- (unsigned long) cred->key_len);
+ (unsigned long) cred->key_len[0]);
}
fprintf(nconf, "auth_algs=1\n");
<at> <at> -352,22 +352,22 <at> <at> static int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred)
else
fprintf(nconf, "auth_algs=1\n");
- if (cred->encr_type & WPS_ENCR_WEP && cred->key_idx <= 4) {
- int key_idx = cred->key_idx;
- if (key_idx)
- key_idx--;
- fprintf(nconf, "wep_default_key=%d\n", key_idx);
- fprintf(nconf, "wep_key%d=", key_idx);
- if (cred->key_len == 10 || cred->key_len == 26) {
- /* WEP key as a hex string */
- for (i = 0; i < cred->key_len; i++)
- fputc(cred->key[i], nconf);
- } else {
- /* Raw WEP key; convert to hex */
- for (i = 0; i < cred->key_len; i++)
- fprintf(nconf, "%02x", cred->key[i]);
+ if (cred->encr_type & WPS_ENCR_WEP && cred->keys_num <= NUM_WEP_KEYS) {
+ u8 j;
+ for (i = 0; i < cred->keys_num; i++) {
+ int len = cred->key_len[i];
+ fprintf(nconf, "wep_key%d=", i);
+ if (len == 10 || len == 26) {
+ /* WEP key[0] as a hex string */
+ for (j = 0; j < len; j++)
+ fputc(cred->key[i][j], nconf);
+ } else {
+ /* Raw WEP key[0]; convert to hex */
+ for (j = 0; j < len; j++)
+ fprintf(nconf, "%02x", cred->key[i][j]);
+ }
+ fprintf(nconf, "\n");
}
- fprintf(nconf, "\n");
}
}
diff --git a/src/wps/wps.h b/src/wps/wps.h
index 9807ad4..6aa64e5 100644
--- a/src/wps/wps.h
+++ b/src/wps/wps.h
<at> <at> -33,6 +33,8 <at> <at> enum wsc_op_code {
struct wps_registrar;
struct upnp_wps_device_sm;
+#define MAX_NW_KEYS 4
+
/**
* struct wps_credential - WPS Credential
* <at> ssid: SSID
<at> <at> -52,9 +54,9 <at> <at> struct wps_credential {
size_t ssid_len;
u16 auth_type;
u16 encr_type;
- u8 key_idx;
- u8 key[64];
- size_t key_len;
+ u8 keys_num;
+ u8 key[MAX_NW_KEYS][64];
+ size_t key_len[MAX_NW_KEYS];
u8 mac_addr[ETH_ALEN];
const u8 *cred_attr;
size_t cred_attr_len;
diff --git a/src/wps/wps_attr_parse.c b/src/wps/wps_attr_parse.c
index 34057c9..08804de 100644
--- a/src/wps/wps_attr_parse.c
+++ b/src/wps/wps_attr_parse.c
<at> <at> -378,8 +378,14 <at> <at> static int wps_set_attr(struct wps_parse_attr *attr, u16 type,
attr->ssid_len = len;
break;
case ATTR_NETWORK_KEY:
- attr->network_key = pos;
- attr->network_key_len = len;
+ if (*attr->network_key_idx > MAX_NW_KEYS) {
+ wpa_printf(MSG_DEBUG, "WPS: Skipped Network Key "
+ "attribute (max %d keys)",
+ MAX_NW_KEYS);
+ break;
+ }
+ attr->network_key[*attr->network_key_idx-1] = pos;
+ attr->network_key_len[*attr->network_key_idx-1] = len;
break;
case ATTR_EAP_TYPE:
attr->eap_type = pos;
diff --git a/src/wps/wps_attr_process.c b/src/wps/wps_attr_process.c
index ae6e906..34efb2a 100644
--- a/src/wps/wps_attr_process.c
+++ b/src/wps/wps_attr_process.c
<at> <at> -164,26 +164,26 <at> <at> static int wps_process_cred_network_key_idx(struct wps_credential *cred,
if (key_idx == NULL)
return 0; /* optional attribute */
- wpa_printf(MSG_DEBUG, "WPS: Network Key Index: %d", *key_idx);
- cred->key_idx = *key_idx;
+ wpa_printf(MSG_DEBUG, "WPS: Network Keys: %d", *key_idx);
+ cred->keys_num = *key_idx;
return 0;
}
-static int wps_process_cred_network_key(struct wps_credential *cred,
- const u8 *key, size_t key_len)
+static int wps_process_cred_network_key(int i, struct wps_credential *cred,
+ const u8 *key[], size_t key_len[])
{
- if (key == NULL) {
+ if (key[i] == NULL) {
wpa_printf(MSG_DEBUG, "WPS: Credential did not include "
- "Network Key");
+ "Network Key %d", i);
return -1;
}
- wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key", key, key_len);
- if (key_len <= sizeof(cred->key)) {
- os_memcpy(cred->key, key, key_len);
- cred->key_len = key_len;
+ wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key", key[i], key_len[i]);
+ if (key_len[i] <= sizeof(cred->key[i])) {
+ os_memcpy(cred->key[i], key[i], key_len[i]);
+ cred->key_len[i] = key_len[i];
}
return 0;
<at> <at> -259,17 +259,23 <at> <at> static int wps_process_cred_802_1x_enabled(struct wps_credential *cred,
static void wps_workaround_cred_key(struct wps_credential *cred)
{
- if (cred->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK) &&
- cred->key_len > 8 && cred->key_len < 64 &&
- cred->key[cred->key_len - 1] == 0) {
- /*
- * A deployed external registrar is known to encode ASCII
- * passphrases incorrectly. Remove the extra NULL termination
- * to fix the encoding.
- */
- wpa_printf(MSG_DEBUG, "WPS: Workaround - remove NULL "
- "termination from ASCII passphrase");
- cred->key_len--;
+ int i;
+
+ if ((cred->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) == 0)
+ return;
+
+ /*
+ * A deployed external registrar is known to encode ASCII
+ * passphrases incorrectly. Remove the extra NULL termination
+ * to fix the encoding.
+ */
+ for (i = 0; i < cred->keys_num; i++) {
+ int len = cred->key_len[i];
+ if (len > 8 && len < 64 && cred->key[len - 1] == 0) {
+ wpa_printf(MSG_DEBUG, "WPS: Workaround - remove NULL "
+ "termination from ASCII passphrase");
+ cred->key_len[i]--;
+ }
}
}
<at> <at> -277,16 +283,15 <at> <at> static void wps_workaround_cred_key(struct wps_credential *cred)
int wps_process_cred(struct wps_parse_attr *attr,
struct wps_credential *cred)
{
+ int i;
+
wpa_printf(MSG_DEBUG, "WPS: Process Credential");
- /* TODO: support multiple Network Keys */
if (wps_process_cred_network_idx(cred, attr->network_idx) ||
wps_process_cred_ssid(cred, attr->ssid, attr->ssid_len) ||
wps_process_cred_auth_type(cred, attr->auth_type) ||
wps_process_cred_encr_type(cred, attr->encr_type) ||
wps_process_cred_network_key_idx(cred, attr->network_key_idx) ||
- wps_process_cred_network_key(cred, attr->network_key,
- attr->network_key_len) ||
wps_process_cred_mac_addr(cred, attr->mac_addr) ||
wps_process_cred_eap_type(cred, attr->eap_type,
attr->eap_type_len) ||
<at> <at> -296,6 +301,11 <at> <at> int wps_process_cred(struct wps_parse_attr *attr,
wps_process_cred_802_1x_enabled(cred, attr->dot1x_enabled))
return -1;
+ for (i = 0; i < cred->keys_num; i++)
+ if (wps_process_cred_network_key(i, cred, attr->network_key,
+ attr->network_key_len))
+ return -1;
+
wps_workaround_cred_key(cred);
return 0;
<at> <at> -312,7 +322,7 <at> <at> int wps_process_ap_settings(struct wps_parse_attr *attr,
wps_process_cred_auth_type(cred, attr->auth_type) ||
wps_process_cred_encr_type(cred, attr->encr_type) ||
wps_process_cred_network_key_idx(cred, attr->network_key_idx) ||
- wps_process_cred_network_key(cred, attr->network_key,
+ wps_process_cred_network_key(0, cred, attr->network_key,
attr->network_key_len) ||
wps_process_cred_mac_addr(cred, attr->mac_addr))
return -1;
diff --git a/src/wps/wps_i.h b/src/wps/wps_i.h
index e3cf236..4ade2c6 100644
--- a/src/wps/wps_i.h
+++ b/src/wps/wps_i.h
<at> <at> -166,8 +166,9 <at> <at> struct wps_parse_attr {
size_t encr_settings_len;
const u8 *ssid; /* <= 32 octets */
size_t ssid_len;
- const u8 *network_key; /* <= 64 octets */
- size_t network_key_len;
+ const u8 *network_key[MAX_NW_KEYS]; /* <= 64 octets */
+ size_t network_key_len[MAX_NW_KEYS];
+ size_t num_nw_key;
const u8 *eap_type; /* <= 8 octets */
size_t eap_type_len;
const u8 *eap_identity; /* <= 64 octets */
diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c
index 185db8c..6890884 100644
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
<at> <at> -1016,8 +1016,8 <at> <at> static int wps_build_cred_network_key(struct wpabuf *msg,
{
wpa_printf(MSG_DEBUG, "WPS: * Network Key");
wpabuf_put_be16(msg, ATTR_NETWORK_KEY);
- wpabuf_put_be16(msg, cred->key_len);
- wpabuf_put_data(msg, cred->key, cred->key_len);
+ wpabuf_put_be16(msg, cred->key_len[0]);
+ wpabuf_put_data(msg, cred->key[0], cred->key_len[0]);
return 0;
}
<at> <at> -1120,11 +1120,11 <at> <at> int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: Generated passphrase",
wps->new_psk, wps->new_psk_len);
os_memcpy(wps->cred.key, wps->new_psk, wps->new_psk_len);
- wps->cred.key_len = wps->new_psk_len;
+ wps->cred.key_len[0] = wps->new_psk_len;
} else if (wps->wps->network_key) {
os_memcpy(wps->cred.key, wps->wps->network_key,
wps->wps->network_key_len);
- wps->cred.key_len = wps->wps->network_key_len;
+ wps->cred.key_len[0] = wps->wps->network_key_len;
} else if (wps->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) {
char hex[65];
/* Generate a random per-device PSK */
<at> <at> -1143,7 +1143,7 <at> <at> int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
wpa_snprintf_hex(hex, sizeof(hex), wps->new_psk,
wps->new_psk_len);
os_memcpy(wps->cred.key, hex, wps->new_psk_len * 2);
- wps->cred.key_len = wps->new_psk_len * 2;
+ wps->cred.key_len[0] = wps->new_psk_len * 2;
}
cred = wpabuf_alloc(200);
<at> <at> -2422,7 +2422,7 <at> <at> static enum wps_process_res wps_process_wsc_done(struct wps_data *wps,
cred.auth_type = WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK;
cred.encr_type = WPS_ENCR_TKIP | WPS_ENCR_AES;
os_memcpy(cred.key, wps->new_psk, wps->new_psk_len);
- cred.key_len = wps->new_psk_len;
+ cred.key_len[0] = wps->new_psk_len;
wps->wps->wps_state = WPS_STATE_CONFIGURED;
wpa_hexdump_ascii_key(MSG_DEBUG,
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index a4efc6e..07aa3f0 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
<at> <at> -187,7 +187,7 <at> <at> static int wpa_supplicant_wps_cred(void *ctx,
{
struct wpa_supplicant *wpa_s = ctx;
struct wpa_ssid *ssid = wpa_s->current_ssid;
- u8 key_idx = 0;
+ u8 i;
if ((wpa_s->conf->wps_cred_processing == 1 ||
wpa_s->conf->wps_cred_processing == 2) && cred->cred_attr) {
<at> <at> -214,9 +214,10 <at> <at> static int wpa_supplicant_wps_cred(void *ctx,
wpa_printf(MSG_DEBUG, "WPS: Authentication Type 0x%x",
cred->auth_type);
wpa_printf(MSG_DEBUG, "WPS: Encryption Type 0x%x", cred->encr_type);
- wpa_printf(MSG_DEBUG, "WPS: Network Key Index %d", cred->key_idx);
- wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key",
- cred->key, cred->key_len);
+ wpa_printf(MSG_DEBUG, "WPS: Network Keys %d", cred->keys_num);
+ for (i = 0; i < cred->keys_num; i++)
+ wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key",
+ cred->key[i], cred->key_len[i]);
wpa_printf(MSG_DEBUG, "WPS: MAC Address " MACSTR,
MAC2STR(cred->mac_addr));
<at> <at> -261,36 +262,35 <at> <at> static int wpa_supplicant_wps_cred(void *ctx,
case WPS_ENCR_NONE:
break;
case WPS_ENCR_WEP:
- if (cred->key_len <= 0)
- break;
- if (cred->key_len != 5 && cred->key_len != 13 &&
- cred->key_len != 10 && cred->key_len != 26) {
- wpa_printf(MSG_ERROR, "WPS: Invalid WEP Key length "
- "%lu", (unsigned long) cred->key_len);
- return -1;
- }
- if (cred->key_idx > NUM_WEP_KEYS) {
- wpa_printf(MSG_ERROR, "WPS: Invalid WEP Key index %d",
- cred->key_idx);
+ if (cred->keys_num > NUM_WEP_KEYS) {
+ wpa_printf(MSG_ERROR, "WPS: Invalid WEP Keys number %d",
+ cred->keys_num);
return -1;
}
- if (cred->key_idx)
- key_idx = cred->key_idx - 1;
- if (cred->key_len == 10 || cred->key_len == 26) {
- if (hexstr2bin((char *) cred->key,
- ssid->wep_key[key_idx],
- cred->key_len / 2) < 0) {
- wpa_printf(MSG_ERROR, "WPS: Invalid WEP Key "
- "%d", key_idx);
+ for (i = 0; i < cred->keys_num; i++) {
+ int len = cred->key_len[i];
+ if (len <= 0)
+ break;
+ if (len != 5 && len != 13 && len != 10 && len != 26) {
+ wpa_printf(MSG_ERROR, "WPS: Invalid WEP Key[%d] length "
+ "%lu", i, (unsigned long) cred->key_len[i]);
return -1;
}
- ssid->wep_key_len[key_idx] = cred->key_len / 2;
- } else {
- os_memcpy(ssid->wep_key[key_idx], cred->key,
- cred->key_len);
- ssid->wep_key_len[key_idx] = cred->key_len;
+ if (len == 10 || len == 26) {
+ if (hexstr2bin((char *) cred->key[i],
+ ssid->wep_key[i],
+ cred->key_len[i] / 2) < 0) {
+ wpa_printf(MSG_ERROR, "WPS: Invalid WEP Key "
+ "%d", i);
+ return -1;
+ }
+ ssid->wep_key_len[i] = cred->key_len[i] / 2;
+ } else {
+ os_memcpy(ssid->wep_key[i], cred->key[i],
+ cred->key_len[i]);
+ ssid->wep_key_len[i] = cred->key_len[i];
+ }
}
- ssid->wep_tx_keyidx = key_idx;
break;
case WPS_ENCR_TKIP:
ssid->pairwise_cipher = WPA_CIPHER_TKIP;
<at> <at> -334,26 +334,26 <at> <at> static int wpa_supplicant_wps_cred(void *ctx,
}
if (ssid->key_mgmt == WPA_KEY_MGMT_PSK) {
- if (cred->key_len == 2 * PMK_LEN) {
- if (hexstr2bin((const char *) cred->key, ssid->psk,
+ if (cred->key_len[0] == 2 * PMK_LEN) {
+ if (hexstr2bin((const char *) cred->key[0], ssid->psk,
PMK_LEN)) {
wpa_printf(MSG_ERROR, "WPS: Invalid Network "
"Key");
return -1;
}
ssid->psk_set = 1;
- } else if (cred->key_len >= 8 && cred->key_len < 2 * PMK_LEN) {
+ } else if (cred->key_len[0] >= 8 && cred->key_len[0] < 2 * PMK_LEN) {
os_free(ssid->passphrase);
- ssid->passphrase = os_malloc(cred->key_len + 1);
+ ssid->passphrase = os_malloc(cred->key_len[0] + 1);
if (ssid->passphrase == NULL)
return -1;
- os_memcpy(ssid->passphrase, cred->key, cred->key_len);
- ssid->passphrase[cred->key_len] = '\0';
+ os_memcpy(ssid->passphrase, cred->key[0], cred->key_len[0]);
+ ssid->passphrase[cred->key_len[0]] = '\0';
wpa_config_update_psk(ssid);
} else {
wpa_printf(MSG_ERROR, "WPS: Invalid Network Key "
"length %lu",
- (unsigned long) cred->key_len);
+ (unsigned long) cred->key_len[0]);
return -1;
}
}
_______________________________________________
HostAP mailing list
HostAP <at> lists.shmoo.com
http://lists.shmoo.com/mailman/listinfo/hostap