WPS: Parse Request Type from WPS IE in (Re)AssocReq and derive mgmt keys
WPS IE is now passed from hostapd association processing into EAP-WSC and WPS processing. Request Type attribute is parsed from this information and if the request is for a WLAN Manager Registrar, additional management keys are derived (to be used with UPnP).
This commit is contained in:
parent
e9ab39b444
commit
eb76b7e3ff
14 changed files with 115 additions and 12 deletions
|
@ -103,6 +103,8 @@ struct sta_info {
|
|||
u8 *ping_trans_id; /* buffer of WLAN_PING_TRANS_ID_LEN * ping_count
|
||||
* octets of pending ping transaction identifiers */
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
|
||||
struct wpabuf *wps_ie; /* WPS IE from (Re)Association Request */
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -813,6 +813,7 @@ eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr,
|
|||
eap_conf.eap_sim_aka_result_ind = eapol->conf.eap_sim_aka_result_ind;
|
||||
eap_conf.tnc = eapol->conf.tnc;
|
||||
eap_conf.wps = eapol->conf.wps;
|
||||
eap_conf.assoc_wps_ie = sta->wps_ie;
|
||||
sm->eap = eap_server_sm_init(sm, &eapol_cb, &eap_conf);
|
||||
if (sm->eap == NULL) {
|
||||
eapol_auth_free(sm);
|
||||
|
|
|
@ -839,6 +839,9 @@ static void handle_assoc(struct hostapd_data *hapd,
|
|||
"(Re)Association Request - assume WPS is "
|
||||
"used");
|
||||
sta->flags |= WLAN_STA_WPS;
|
||||
wpabuf_free(sta->wps_ie);
|
||||
sta->wps_ie = wpabuf_alloc_copy(elems.wps_ie + 4,
|
||||
elems.wps_ie_len - 4);
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG, "STA did not include WPA/RSN IE "
|
||||
"in (Re)Association Request - possible WPS "
|
||||
|
|
|
@ -188,6 +188,8 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
|||
eloop_cancel_timeout(ap_ping_timer, hapd, sta);
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
|
||||
wpabuf_free(sta->wps_ie);
|
||||
|
||||
os_free(sta);
|
||||
}
|
||||
|
||||
|
|
|
@ -1167,6 +1167,8 @@ struct eap_sm * eap_server_sm_init(void *eapol_ctx,
|
|||
sm->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
|
||||
sm->tnc = conf->tnc;
|
||||
sm->wps = conf->wps;
|
||||
if (conf->assoc_wps_ie)
|
||||
sm->assoc_wps_ie = wpabuf_dup(conf->assoc_wps_ie);
|
||||
|
||||
wpa_printf(MSG_DEBUG, "EAP: Server state machine created");
|
||||
|
||||
|
@ -1200,6 +1202,7 @@ void eap_server_sm_deinit(struct eap_sm *sm)
|
|||
wpabuf_free(sm->eap_if.aaaEapRespData);
|
||||
os_free(sm->eap_if.aaaEapKeyData);
|
||||
eap_user_free(sm->user);
|
||||
wpabuf_free(sm->assoc_wps_ie);
|
||||
os_free(sm);
|
||||
}
|
||||
|
||||
|
|
|
@ -104,6 +104,7 @@ struct eap_config {
|
|||
int eap_sim_aka_result_ind;
|
||||
int tnc;
|
||||
struct wps_context *wps;
|
||||
const struct wpabuf *assoc_wps_ie;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -182,6 +182,7 @@ struct eap_sm {
|
|||
int eap_sim_aka_result_ind;
|
||||
int tnc;
|
||||
struct wps_context *wps;
|
||||
struct wpabuf *assoc_wps_ie;
|
||||
};
|
||||
|
||||
int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* EAP-WSC server for Wi-Fi Protected Setup
|
||||
* Copyright (c) 2007, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2007-2008, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
|
@ -109,6 +109,7 @@ static void * eap_wsc_init(struct eap_sm *sm)
|
|||
cfg.pin = sm->user->password;
|
||||
cfg.pin_len = sm->user->password_len;
|
||||
}
|
||||
cfg.assoc_wps_ie = sm->assoc_wps_ie;
|
||||
data->wps = wps_init(&cfg);
|
||||
if (data->wps == NULL) {
|
||||
os_free(data);
|
||||
|
|
|
@ -60,6 +60,24 @@ struct wps_data * wps_init(const struct wps_config *cfg)
|
|||
|
||||
data->state = data->registrar ? RECV_M1 : SEND_M1;
|
||||
|
||||
if (cfg->assoc_wps_ie) {
|
||||
struct wps_parse_attr attr;
|
||||
wpa_hexdump_buf(MSG_DEBUG, "WPS: WPS IE from (Re)AssocReq",
|
||||
cfg->assoc_wps_ie);
|
||||
if (wps_parse_msg(cfg->assoc_wps_ie, &attr) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Failed to parse WPS IE "
|
||||
"from (Re)AssocReq");
|
||||
} else if (attr.request_type == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: No Request Type attribute "
|
||||
"in (Re)AssocReq WPS IE");
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Request Type (from WPS IE "
|
||||
"in (Re)AssocReq WPS IE): %d",
|
||||
*attr.request_type);
|
||||
data->request_type = *attr.request_type;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ struct wps_config {
|
|||
size_t pin_len;
|
||||
const u8 *uuid; /* 128-bit Enrollee UUID (NULL for Registrar) */
|
||||
int pbc;
|
||||
const struct wpabuf *assoc_wps_ie; /* (Re)AssocReq WPS IE (in AP) */
|
||||
};
|
||||
|
||||
struct wps_data * wps_init(const struct wps_config *cfg);
|
||||
|
|
|
@ -433,11 +433,12 @@ int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr)
|
|||
}
|
||||
|
||||
|
||||
void wps_kdf(const u8 *key, const char *label, u8 *res, size_t res_len)
|
||||
void wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len,
|
||||
const char *label, u8 *res, size_t res_len)
|
||||
{
|
||||
u8 i_buf[4], key_bits[4];
|
||||
const u8 *addr[3];
|
||||
size_t len[3];
|
||||
const u8 *addr[4];
|
||||
size_t len[4];
|
||||
int i, iter;
|
||||
u8 hash[SHA256_MAC_LEN], *opos;
|
||||
size_t left;
|
||||
|
@ -446,10 +447,12 @@ void wps_kdf(const u8 *key, const char *label, u8 *res, size_t res_len)
|
|||
|
||||
addr[0] = i_buf;
|
||||
len[0] = sizeof(i_buf);
|
||||
addr[1] = (const u8 *) label;
|
||||
len[1] = os_strlen(label);
|
||||
addr[2] = key_bits;
|
||||
len[2] = sizeof(key_bits);
|
||||
addr[1] = label_prefix;
|
||||
len[1] = label_prefix_len;
|
||||
addr[2] = (const u8 *) label;
|
||||
len[2] = os_strlen(label);
|
||||
addr[3] = key_bits;
|
||||
len[3] = sizeof(key_bits);
|
||||
|
||||
iter = (res_len + SHA256_MAC_LEN - 1) / SHA256_MAC_LEN;
|
||||
opos = res;
|
||||
|
@ -457,7 +460,7 @@ void wps_kdf(const u8 *key, const char *label, u8 *res, size_t res_len)
|
|||
|
||||
for (i = 1; i <= iter; i++) {
|
||||
WPA_PUT_BE32(i_buf, i);
|
||||
hmac_sha256_vector(key, SHA256_MAC_LEN, 3, addr, len, hash);
|
||||
hmac_sha256_vector(key, SHA256_MAC_LEN, 4, addr, len, hash);
|
||||
if (i < iter) {
|
||||
os_memcpy(opos, hash, SHA256_MAC_LEN);
|
||||
opos += SHA256_MAC_LEN;
|
||||
|
@ -545,7 +548,7 @@ int wps_derive_keys(struct wps_data *wps)
|
|||
hmac_sha256_vector(dhkey, sizeof(dhkey), 3, addr, len, kdk);
|
||||
wpa_hexdump_key(MSG_DEBUG, "WPS: KDK", kdk, sizeof(kdk));
|
||||
|
||||
wps_kdf(kdk, "Wi-Fi Easy and Secure Key Derivation",
|
||||
wps_kdf(kdk, NULL, 0, "Wi-Fi Easy and Secure Key Derivation",
|
||||
keys, sizeof(keys));
|
||||
os_memcpy(wps->authkey, keys, WPS_AUTHKEY_LEN);
|
||||
os_memcpy(wps->keywrapkey, keys + WPS_AUTHKEY_LEN, WPS_KEYWRAPKEY_LEN);
|
||||
|
@ -562,6 +565,56 @@ int wps_derive_keys(struct wps_data *wps)
|
|||
}
|
||||
|
||||
|
||||
int wps_derive_mgmt_keys(struct wps_data *wps)
|
||||
{
|
||||
u8 nonces[2 * WPS_NONCE_LEN];
|
||||
u8 keys[WPS_MGMTAUTHKEY_LEN + WPS_MGMTENCKEY_LEN];
|
||||
u8 hash[SHA256_MAC_LEN];
|
||||
const u8 *addr[2];
|
||||
size_t len[2];
|
||||
const char *auth_label = "WFA-WLAN-Management-MgmtAuthKey";
|
||||
const char *enc_label = "WFA-WLAN-Management-MgmtEncKey";
|
||||
|
||||
/* MgmtAuthKey || MgmtEncKey =
|
||||
* kdf(EMSK, N1 || N2 || "WFA-WLAN-Management-Keys", 384) */
|
||||
os_memcpy(nonces, wps->nonce_e, WPS_NONCE_LEN);
|
||||
os_memcpy(nonces + WPS_NONCE_LEN, wps->nonce_r, WPS_NONCE_LEN);
|
||||
wps_kdf(wps->emsk, nonces, sizeof(nonces), "WFA-WLAN-Management-Keys",
|
||||
keys, sizeof(keys));
|
||||
os_memcpy(wps->mgmt_auth_key, keys, WPS_MGMTAUTHKEY_LEN);
|
||||
os_memcpy(wps->mgmt_enc_key, keys + WPS_MGMTAUTHKEY_LEN,
|
||||
WPS_MGMTENCKEY_LEN);
|
||||
|
||||
addr[0] = nonces;
|
||||
len[0] = sizeof(nonces);
|
||||
|
||||
/* MgmtEncKeyID = first 128 bits of
|
||||
* SHA-256(N1 || N2 || "WFA-WLAN-Management-MgmtAuthKey") */
|
||||
addr[1] = (const u8 *) auth_label;
|
||||
len[1] = os_strlen(auth_label);
|
||||
sha256_vector(2, addr, len, hash);
|
||||
os_memcpy(wps->mgmt_auth_key_id, hash, WPS_MGMT_KEY_ID_LEN);
|
||||
|
||||
/* MgmtEncKeyID = first 128 bits of
|
||||
* SHA-256(N1 || N2 || "WFA-WLAN-Management-MgmtEncKey") */
|
||||
addr[1] = (const u8 *) enc_label;
|
||||
len[1] = os_strlen(enc_label);
|
||||
sha256_vector(2, addr, len, hash);
|
||||
os_memcpy(wps->mgmt_enc_key_id, hash, WPS_MGMT_KEY_ID_LEN);
|
||||
|
||||
wpa_hexdump_key(MSG_DEBUG, "WPS: MgmtAuthKey",
|
||||
wps->mgmt_auth_key, WPS_MGMTAUTHKEY_LEN);
|
||||
wpa_hexdump(MSG_DEBUG, "WPS: MgmtAuthKeyID",
|
||||
wps->mgmt_auth_key_id, WPS_MGMT_KEY_ID_LEN);
|
||||
wpa_hexdump_key(MSG_DEBUG, "WPS: MgmtEncKey",
|
||||
wps->mgmt_enc_key, WPS_MGMTENCKEY_LEN);
|
||||
wpa_hexdump(MSG_DEBUG, "WPS: MgmtEncKeyID",
|
||||
wps->mgmt_enc_key_id, WPS_MGMT_KEY_ID_LEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wps_build_authenticator(struct wps_data *wps, struct wpabuf *msg)
|
||||
{
|
||||
u8 hash[SHA256_MAC_LEN];
|
||||
|
|
|
@ -30,6 +30,9 @@
|
|||
#define WPS_SECRET_NONCE_LEN 16
|
||||
#define WPS_HASH_LEN 32
|
||||
#define WPS_KWA_LEN 8
|
||||
#define WPS_MGMTAUTHKEY_LEN 32
|
||||
#define WPS_MGMTENCKEY_LEN 16
|
||||
#define WPS_MGMT_KEY_ID_LEN 16
|
||||
|
||||
/* Attribute Types */
|
||||
enum wps_attribute {
|
||||
|
|
|
@ -553,7 +553,14 @@ static int wps_process_pubkey(struct wps_data *wps, const u8 *pk,
|
|||
if (wps->dh_pubkey_r == NULL)
|
||||
return -1;
|
||||
|
||||
return wps_derive_keys(wps);
|
||||
if (wps_derive_keys(wps) < 0)
|
||||
return -1;
|
||||
|
||||
if (wps->request_type == WPS_REQ_WLAN_MANAGER_REGISTRAR &&
|
||||
wps_derive_mgmt_keys(wps) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -56,6 +56,10 @@ struct wps_data {
|
|||
u8 authkey[WPS_AUTHKEY_LEN];
|
||||
u8 keywrapkey[WPS_KEYWRAPKEY_LEN];
|
||||
u8 emsk[WPS_EMSK_LEN];
|
||||
u8 mgmt_auth_key[WPS_MGMTAUTHKEY_LEN];
|
||||
u8 mgmt_auth_key_id[WPS_MGMT_KEY_ID_LEN];
|
||||
u8 mgmt_enc_key[WPS_MGMTENCKEY_LEN];
|
||||
u8 mgmt_enc_key_id[WPS_MGMT_KEY_ID_LEN];
|
||||
|
||||
struct wpabuf *last_msg;
|
||||
|
||||
|
@ -63,6 +67,7 @@ struct wps_data {
|
|||
size_t dev_password_len;
|
||||
u16 dev_pw_id;
|
||||
int pbc;
|
||||
u8 request_type; /* Request Type attribute from (Re)AssocReq */
|
||||
|
||||
u16 encr_type; /* available encryption types */
|
||||
u16 auth_type; /* available authentication types */
|
||||
|
@ -151,9 +156,11 @@ struct wps_parse_attr {
|
|||
|
||||
/* wps_common.c */
|
||||
int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr);
|
||||
void wps_kdf(const u8 *key, const char *label, u8 *res, size_t res_len);
|
||||
void wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len,
|
||||
const char *label, u8 *res, size_t res_len);
|
||||
int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg);
|
||||
int wps_derive_keys(struct wps_data *wps);
|
||||
int wps_derive_mgmt_keys(struct wps_data *wps);
|
||||
int wps_build_authenticator(struct wps_data *wps, struct wpabuf *msg);
|
||||
int wps_process_authenticator(struct wps_data *wps, const u8 *authenticator,
|
||||
const struct wpabuf *msg);
|
||||
|
|
Loading…
Reference in a new issue