Updated through tag hostap_2_5 from git://w1.fi/hostap.git
[mech_eap.git] / libeap / src / wps / wps_attr_build.c
index 681c465..b689357 100644 (file)
@@ -2,14 +2,8 @@
  * Wi-Fi Protected Setup - attribute building
  * Copyright (c) 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
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -19,6 +13,7 @@
 #include "crypto/crypto.h"
 #include "crypto/dh_group5.h"
 #include "crypto/sha256.h"
+#include "crypto/random.h"
 #include "common/ieee802_11_defs.h"
 #include "wps_i.h"
 
@@ -29,15 +24,46 @@ int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg)
 
        wpa_printf(MSG_DEBUG, "WPS:  * Public Key");
        wpabuf_free(wps->dh_privkey);
-       if (wps->dev_pw_id != DEV_PW_DEFAULT && wps->wps->dh_privkey) {
+       wps->dh_privkey = NULL;
+       if (wps->dev_pw_id != DEV_PW_DEFAULT && wps->wps->dh_privkey &&
+           wps->wps->dh_ctx) {
                wpa_printf(MSG_DEBUG, "WPS: Using pre-configured DH keys");
+               if (wps->wps->dh_pubkey == NULL) {
+                       wpa_printf(MSG_DEBUG,
+                                  "WPS: wps->wps->dh_pubkey == NULL");
+                       return -1;
+               }
                wps->dh_privkey = wpabuf_dup(wps->wps->dh_privkey);
                wps->dh_ctx = wps->wps->dh_ctx;
                wps->wps->dh_ctx = NULL;
                pubkey = wpabuf_dup(wps->wps->dh_pubkey);
+#ifdef CONFIG_WPS_NFC
+       } else if ((wps->dev_pw_id >= 0x10 ||
+                   wps->dev_pw_id == DEV_PW_NFC_CONNECTION_HANDOVER) &&
+                  (wps->wps->ap ||
+                   (wps->wps->ap_nfc_dh_pubkey &&
+                    wps->wps->ap_nfc_dev_pw_id ==
+                    DEV_PW_NFC_CONNECTION_HANDOVER &&
+                    wps->dev_pw_id == DEV_PW_NFC_CONNECTION_HANDOVER)) &&
+                  (wps->dev_pw_id == wps->wps->ap_nfc_dev_pw_id ||
+                   wps->wps->ap_nfc_dh_pubkey)) {
+               wpa_printf(MSG_DEBUG, "WPS: Using NFC password token DH keys");
+               if (wps->wps->ap_nfc_dh_privkey == NULL) {
+                       wpa_printf(MSG_DEBUG,
+                                  "WPS: wps->wps->ap_nfc_dh_privkey == NULL");
+                       return -1;
+               }
+               if (wps->wps->ap_nfc_dh_pubkey == NULL) {
+                       wpa_printf(MSG_DEBUG,
+                                  "WPS: wps->wps->ap_nfc_dh_pubkey == NULL");
+                       return -1;
+               }
+               wps->dh_privkey = wpabuf_dup(wps->wps->ap_nfc_dh_privkey);
+               pubkey = wpabuf_dup(wps->wps->ap_nfc_dh_pubkey);
+               wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, pubkey);
+#endif /* CONFIG_WPS_NFC */
        } else {
                wpa_printf(MSG_DEBUG, "WPS: Generate new DH keys");
-               wps->dh_privkey = NULL;
                dh5_free(wps->dh_ctx);
                wps->dh_ctx = dh5_init(&wps->dh_privkey, &pubkey);
                pubkey = wpabuf_zeropad(pubkey, 192);
@@ -99,6 +125,8 @@ int wps_build_config_methods(struct wpabuf *msg, u16 methods)
 
 int wps_build_uuid_e(struct wpabuf *msg, const u8 *uuid)
 {
+       if (wpabuf_tailroom(msg) < 4 + WPS_UUID_LEN)
+               return -1;
        wpa_printf(MSG_DEBUG, "WPS:  * UUID-E");
        wpabuf_put_be16(msg, ATTR_UUID_E);
        wpabuf_put_be16(msg, WPS_UUID_LEN);
@@ -164,6 +192,8 @@ int wps_build_version(struct wpabuf *msg)
         * backwards compatibility reasons. The real version negotiation is
         * done with Version2.
         */
+       if (wpabuf_tailroom(msg) < 5)
+               return -1;
        wpa_printf(MSG_DEBUG, "WPS:  * Version (hardcoded 0x10)");
        wpabuf_put_be16(msg, ATTR_VERSION);
        wpabuf_put_be16(msg, 1);
@@ -175,9 +205,17 @@ int wps_build_version(struct wpabuf *msg)
 int wps_build_wfa_ext(struct wpabuf *msg, int req_to_enroll,
                      const u8 *auth_macs, size_t auth_macs_count)
 {
-#ifdef CONFIG_WPS2
        u8 *len;
 
+#ifdef CONFIG_WPS_TESTING
+       if (WPS_VERSION == 0x10)
+               return 0;
+#endif /* CONFIG_WPS_TESTING */
+
+       if (wpabuf_tailroom(msg) <
+           7 + 3 + (req_to_enroll ? 3 : 0) +
+           (auth_macs ? 2 + auth_macs_count * ETH_ALEN : 0))
+               return -1;
        wpabuf_put_be16(msg, ATTR_VENDOR_EXT);
        len = wpabuf_put(msg, 2); /* to be filled */
        wpabuf_put_be24(msg, WPS_VENDOR_ID_WFA);
@@ -207,10 +245,11 @@ int wps_build_wfa_ext(struct wpabuf *msg, int req_to_enroll,
        }
 
        WPA_PUT_BE16(len, (u8 *) wpabuf_put(msg, 0) - len - 2);
-#endif /* CONFIG_WPS2 */
 
 #ifdef CONFIG_WPS_TESTING
        if (WPS_VERSION > 0x20) {
+               if (wpabuf_tailroom(msg) < 5)
+                       return -1;
                wpa_printf(MSG_DEBUG, "WPS:  * Extensibility Testing - extra "
                           "attribute");
                wpabuf_put_be16(msg, ATTR_EXTENSIBILITY_TEST);
@@ -254,20 +293,27 @@ int wps_build_registrar_nonce(struct wps_data *wps, struct wpabuf *msg)
 
 int wps_build_auth_type_flags(struct wps_data *wps, struct wpabuf *msg)
 {
+       u16 auth_types = WPS_AUTH_TYPES;
+       /* WPA/WPA2-Enterprise enrollment not supported through WPS */
+       auth_types &= ~WPS_AUTH_WPA;
+       auth_types &= ~WPS_AUTH_WPA2;
+       auth_types &= ~WPS_AUTH_SHARED;
        wpa_printf(MSG_DEBUG, "WPS:  * Authentication Type Flags");
        wpabuf_put_be16(msg, ATTR_AUTH_TYPE_FLAGS);
        wpabuf_put_be16(msg, 2);
-       wpabuf_put_be16(msg, WPS_AUTH_TYPES);
+       wpabuf_put_be16(msg, auth_types);
        return 0;
 }
 
 
 int wps_build_encr_type_flags(struct wps_data *wps, struct wpabuf *msg)
 {
+       u16 encr_types = WPS_ENCR_TYPES;
+       encr_types &= ~WPS_ENCR_WEP;
        wpa_printf(MSG_DEBUG, "WPS:  * Encryption Type Flags");
        wpabuf_put_be16(msg, ATTR_ENCR_TYPE_FLAGS);
        wpabuf_put_be16(msg, 2);
-       wpabuf_put_be16(msg, WPS_ENCR_TYPES);
+       wpabuf_put_be16(msg, encr_types);
        return 0;
 }
 
@@ -324,7 +370,7 @@ int wps_build_encr_settings(struct wps_data *wps, struct wpabuf *msg,
        wpabuf_put_be16(msg, block_size + wpabuf_len(plain));
 
        iv = wpabuf_put(msg, block_size);
-       if (os_get_random(iv, block_size) < 0)
+       if (random_get_bytes(iv, block_size) < 0)
                return -1;
 
        data = wpabuf_put(msg, 0);
@@ -337,43 +383,39 @@ int wps_build_encr_settings(struct wps_data *wps, struct wpabuf *msg,
 
 
 #ifdef CONFIG_WPS_OOB
-int wps_build_oob_dev_password(struct wpabuf *msg, struct wps_context *wps)
+int wps_build_oob_dev_pw(struct wpabuf *msg, u16 dev_pw_id,
+                        const struct wpabuf *pubkey, const u8 *dev_pw,
+                        size_t dev_pw_len)
 {
        size_t hash_len;
        const u8 *addr[1];
        u8 pubkey_hash[WPS_HASH_LEN];
-       u8 dev_password_bin[WPS_OOB_DEVICE_PASSWORD_LEN];
-
-       wpa_printf(MSG_DEBUG, "WPS:  * OOB Device Password");
 
-       addr[0] = wpabuf_head(wps->dh_pubkey);
-       hash_len = wpabuf_len(wps->dh_pubkey);
+       wpa_printf(MSG_DEBUG, "WPS:  * OOB Device Password (dev_pw_id=%u)",
+                  dev_pw_id);
+       addr[0] = wpabuf_head(pubkey);
+       hash_len = wpabuf_len(pubkey);
        sha256_vector(1, addr, &hash_len, pubkey_hash);
-
-       if (os_get_random((u8 *) &wps->oob_dev_pw_id, sizeof(u16)) < 0) {
-               wpa_printf(MSG_ERROR, "WPS: device password id "
-                          "generation error");
-               return -1;
-       }
-       wps->oob_dev_pw_id |= 0x0010;
-
-       if (os_get_random(dev_password_bin, WPS_OOB_DEVICE_PASSWORD_LEN) < 0) {
-               wpa_printf(MSG_ERROR, "WPS: OOB device password "
-                          "generation error");
-               return -1;
+#ifdef CONFIG_WPS_TESTING
+       if (wps_corrupt_pkhash) {
+               wpa_hexdump(MSG_DEBUG, "WPS: Real Public Key Hash",
+                           pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN);
+               wpa_printf(MSG_INFO, "WPS: Testing - corrupt public key hash");
+               pubkey_hash[WPS_OOB_PUBKEY_HASH_LEN - 2]++;
        }
+#endif /* CONFIG_WPS_TESTING */
 
        wpabuf_put_be16(msg, ATTR_OOB_DEVICE_PASSWORD);
-       wpabuf_put_be16(msg, WPS_OOB_DEVICE_PASSWORD_ATTR_LEN);
+       wpabuf_put_be16(msg, WPS_OOB_PUBKEY_HASH_LEN + 2 + dev_pw_len);
+       wpa_hexdump(MSG_DEBUG, "WPS: Public Key Hash",
+                   pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN);
        wpabuf_put_data(msg, pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN);
-       wpabuf_put_be16(msg, wps->oob_dev_pw_id);
-       wpabuf_put_data(msg, dev_password_bin, WPS_OOB_DEVICE_PASSWORD_LEN);
-
-       wpa_snprintf_hex_uppercase(
-               wpabuf_put(wps->oob_conf.dev_password,
-                          wpabuf_size(wps->oob_conf.dev_password)),
-               wpabuf_size(wps->oob_conf.dev_password),
-               dev_password_bin, WPS_OOB_DEVICE_PASSWORD_LEN);
+       wpabuf_put_be16(msg, dev_pw_id);
+       if (dev_pw) {
+               wpa_hexdump_key(MSG_DEBUG, "WPS: OOB Device Password",
+                               dev_pw, dev_pw_len);
+               wpabuf_put_data(msg, dev_pw, dev_pw_len);
+       }
 
        return 0;
 }
@@ -410,3 +452,34 @@ struct wpabuf * wps_ie_encapsulate(struct wpabuf *data)
 
        return ie;
 }
+
+
+int wps_build_mac_addr(struct wpabuf *msg, const u8 *addr)
+{
+       wpa_printf(MSG_DEBUG, "WPS:  * MAC Address (" MACSTR ")",
+                  MAC2STR(addr));
+       wpabuf_put_be16(msg, ATTR_MAC_ADDR);
+       wpabuf_put_be16(msg, ETH_ALEN);
+       wpabuf_put_data(msg, addr, ETH_ALEN);
+       return 0;
+}
+
+
+int wps_build_rf_bands_attr(struct wpabuf *msg, u8 rf_bands)
+{
+       wpa_printf(MSG_DEBUG, "WPS:  * RF Bands (%x)", rf_bands);
+       wpabuf_put_be16(msg, ATTR_RF_BANDS);
+       wpabuf_put_be16(msg, 1);
+       wpabuf_put_u8(msg, rf_bands);
+       return 0;
+}
+
+
+int wps_build_ap_channel(struct wpabuf *msg, u16 ap_channel)
+{
+       wpa_printf(MSG_DEBUG, "WPS:  * AP Channel (%u)", ap_channel);
+       wpabuf_put_be16(msg, ATTR_AP_CHANNEL);
+       wpabuf_put_be16(msg, 2);
+       wpabuf_put_be16(msg, ap_channel);
+       return 0;
+}