]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
WPS: Parse Request Type from WPS IE in (Re)AssocReq and derive mgmt keys
authorJouni Malinen <j@w1.fi>
Sat, 29 Nov 2008 10:11:56 +0000 (12:11 +0200)
committerJouni Malinen <j@w1.fi>
Sat, 29 Nov 2008 10:11:56 +0000 (12:11 +0200)
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).

14 files changed:
hostapd/ap.h
hostapd/eapol_sm.c
hostapd/ieee802_11.c
hostapd/sta_info.c
src/eap_server/eap.c
src/eap_server/eap.h
src/eap_server/eap_i.h
src/eap_server/eap_wsc.c
src/wps/wps.c
src/wps/wps.h
src/wps/wps_common.c
src/wps/wps_defs.h
src/wps/wps_enrollee.c
src/wps/wps_i.h

index f6596fe569b6c30a8dadd0f3698ac3e09ec569d8..380b7863ed1bd66b9e05d2452a9a089fa0679677 100644 (file)
@@ -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 */
 };
 
 
index b333db73ce96adeacbfcedd202af65dad2e45583..826d71d7490261f619f2d05b3c1a63f3b0adc6f7 100644 (file)
@@ -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);
index 23cc9eb48f38d07e2d4ddeb2f77a7308920899a8..eac43cf3ba03fb11c52218d1bfc65b60d3a6f51e 100644 (file)
@@ -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 "
index b2ebe062fa3d587fe3ad2384116ab524f392d0d3..6fc1e0435498c35b49543538ea5396cb28dbaa20 100644 (file)
@@ -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);
 }
 
index 37b136bd934b57849b87d45d7cab05da927bfce4..f3f81f35e0b1566a7ece94c1868fdf8ee26a3899 100644 (file)
@@ -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);
 }
 
index 8a918eb76ce92b5d75ceb62f84756526d60fbdfc..6a20da4f46b0b1d27e1579fb1ae7ba80e164a498 100644 (file)
@@ -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;
 };
 
 
index 439e1efe65fd715264ac85379475bd8ce5827c46..61f564d5c49f3bdb7a24364b572f900216c8d6c1 100644 (file)
@@ -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,
index b81b5390886855987602afcfd14117f73f09af6b..62666363525e8f2107a6d750c2dbe56434351cd8 100644 (file)
@@ -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);
index 2b3751dd876b0082026fc25a3a61ac453b805000..8dbab5e562b2ce95a13a3eb8feffaf0be36543c9 100644 (file)
@@ -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;
 }
 
index 0d08e1acdafaab910fd392963f7372438a575963..e206c2d07268965dc9d18851aa459711c6a6f05a 100644 (file)
@@ -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);
index 1a4ae036382d82562d5bea94fa1067f0f916c183..64f0a4d2761764b8152b1c4d4f046a6fc51a2a36 100644 (file)
@@ -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];
index 141efba0625f80310c3f837cc25bed0cb78ae741..bf6ccc5f3ecbaae8d1c4ccb555f13dbf45a88017 100644 (file)
@@ -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 {
index d89ca3d98f9db096736b49ed200fd72c10c04618..4a0058aa3d0bcb56f2223075e803906276c432e2 100644 (file)
@@ -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;
 }
 
 
index 8d6242b935aa3fec542417368ee09b571a5fe5cc..7f5f5ea7f1af6643ec7f8290d2e6ea6810792874 100644 (file)
@@ -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);