]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
DPP: Configurator in hostapd
authorJouni Malinen <jouni@qca.qualcomm.com>
Mon, 3 Jul 2017 09:56:48 +0000 (12:56 +0300)
committerJouni Malinen <j@w1.fi>
Mon, 3 Jul 2017 10:03:35 +0000 (13:03 +0300)
This integrates DPP configuration request processing into hostapd GAS
server implementation.

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
hostapd/ctrl_iface.c
src/ap/dpp_hostapd.c
src/ap/dpp_hostapd.h
src/ap/gas_serv.c
src/ap/gas_serv.h
src/ap/hostapd.h

index 1ac0092124b8908cca7ec8ec6000144e52d29125..e5c7e99622e8d4e389b05a466a179e193e4d3afa 100644 (file)
@@ -2688,6 +2688,18 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
        } else if (os_strncmp(buf, "DPP_AUTH_INIT ", 14) == 0) {
                if (hostapd_dpp_auth_init(hapd, buf + 13) < 0)
                        reply_len = -1;
+       } else if (os_strncmp(buf, "DPP_CONFIGURATOR_ADD", 20) == 0) {
+               res = hostapd_dpp_configurator_add(hapd, buf + 20);
+               if (res < 0) {
+                       reply_len = -1;
+               } else {
+                       reply_len = os_snprintf(reply, reply_size, "%d", res);
+                       if (os_snprintf_error(reply_size, reply_len))
+                               reply_len = -1;
+               }
+       } else if (os_strncmp(buf, "DPP_CONFIGURATOR_REMOVE ", 24) == 0) {
+               if (hostapd_dpp_configurator_remove(hapd, buf + 24) < 0)
+                       reply_len = -1;
        } else if (os_strncmp(buf, "DPP_PKEX_ADD ", 13) == 0) {
                res = hostapd_dpp_pkex_add(hapd, buf + 12);
                if (res < 0) {
index 21f5aa89c629b56b097f1fd58bbda125dd5254fe..648ae6503e04df1e56583d15d08523af1a9b3616 100644 (file)
@@ -1142,6 +1142,127 @@ void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src,
 }
 
 
+struct wpabuf *
+hostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa,
+                           const u8 *query, size_t query_len)
+{
+       struct dpp_authentication *auth = hapd->dpp_auth;
+       struct wpabuf *resp;
+
+       wpa_printf(MSG_DEBUG, "DPP: GAS request from " MACSTR, MAC2STR(sa));
+       if (!auth || !auth->auth_success ||
+           os_memcmp(sa, auth->peer_mac_addr, ETH_ALEN) != 0) {
+               wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
+               return NULL;
+       }
+       wpa_hexdump(MSG_DEBUG,
+                   "DPP: Received Configuration Request (GAS Query Request)",
+                   query, query_len);
+       resp = dpp_conf_req_rx(auth, query, query_len);
+       if (!resp)
+               wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
+       return resp;
+}
+
+
+static unsigned int hostapd_dpp_next_configurator_id(struct hostapd_data *hapd)
+{
+       struct dpp_configurator *conf;
+       unsigned int max_id = 0;
+
+       dl_list_for_each(conf, &hapd->dpp_configurator,
+                        struct dpp_configurator, list) {
+               if (conf->id > max_id)
+                       max_id = conf->id;
+       }
+       return max_id + 1;
+}
+
+
+int hostapd_dpp_configurator_add(struct hostapd_data *hapd, const char *cmd)
+{
+       char *expiry = NULL, *curve = NULL;
+       char *key = NULL;
+       u8 *privkey = NULL;
+       size_t privkey_len = 0;
+       int ret = -1;
+       struct dpp_configurator *conf = NULL;
+
+       expiry = get_param(cmd, " expiry=");
+       curve = get_param(cmd, " curve=");
+       key = get_param(cmd, " key=");
+
+       if (key) {
+               privkey_len = os_strlen(key) / 2;
+               privkey = os_malloc(privkey_len);
+               if (!privkey ||
+                   hexstr2bin(key, privkey, privkey_len) < 0)
+                       goto fail;
+       }
+
+       conf = dpp_keygen_configurator(curve, privkey, privkey_len);
+       if (!conf)
+               goto fail;
+
+       if (expiry) {
+               long int val;
+
+               val = strtol(expiry, NULL, 0);
+               if (val <= 0)
+                       goto fail;
+               conf->csign_expiry = val;
+       }
+
+       conf->id = hostapd_dpp_next_configurator_id(hapd);
+       dl_list_add(&hapd->dpp_configurator, &conf->list);
+       ret = conf->id;
+       conf = NULL;
+fail:
+       os_free(curve);
+       os_free(expiry);
+       str_clear_free(key);
+       bin_clear_free(privkey, privkey_len);
+       dpp_configurator_free(conf);
+       return ret;
+}
+
+
+static int dpp_configurator_del(struct hostapd_data *hapd, unsigned int id)
+{
+       struct dpp_configurator *conf, *tmp;
+       int found = 0;
+
+       dl_list_for_each_safe(conf, tmp, &hapd->dpp_configurator,
+                             struct dpp_configurator, list) {
+               if (id && conf->id != id)
+                       continue;
+               found = 1;
+               dl_list_del(&conf->list);
+               dpp_configurator_free(conf);
+       }
+
+       if (id == 0)
+               return 0; /* flush succeeds regardless of entries found */
+       return found ? 0 : -1;
+}
+
+
+int hostapd_dpp_configurator_remove(struct hostapd_data *hapd, const char *id)
+{
+       unsigned int id_val;
+
+       if (os_strcmp(id, "*") == 0) {
+               id_val = 0;
+       } else {
+               id_val = atoi(id);
+               if (id_val == 0)
+                       return -1;
+       }
+
+       return dpp_configurator_del(hapd, id_val);
+}
+
+
 int hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd)
 {
        struct dpp_bootstrap_info *own_bi;
@@ -1246,6 +1367,7 @@ int hostapd_dpp_pkex_remove(struct hostapd_data *hapd, const char *id)
 int hostapd_dpp_init(struct hostapd_data *hapd)
 {
        dl_list_init(&hapd->dpp_bootstrap);
+       dl_list_init(&hapd->dpp_configurator);
        hapd->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE;
        hapd->dpp_init_done = 1;
        return 0;
@@ -1268,6 +1390,7 @@ void hostapd_dpp_deinit(struct hostapd_data *hapd)
        if (!hapd->dpp_init_done)
                return;
        dpp_bootstrap_del(hapd, 0);
+       dpp_configurator_del(hapd, 0);
        dpp_auth_deinit(hapd->dpp_auth);
        hapd->dpp_auth = NULL;
        hostapd_dpp_pkex_remove(hapd, "*");
index 4a585a1cd925af663eae9522fd8bfd2435aa6ef7..9aa08305da01e38fae123c3129bce688f63bde13 100644 (file)
@@ -19,6 +19,11 @@ void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src,
                           const u8 *buf, size_t len, unsigned int freq);
 void hostapd_dpp_tx_status(struct hostapd_data *hapd, const u8 *dst,
                           const u8 *data, size_t data_len, int ok);
+struct wpabuf *
+hostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa,
+                           const u8 *query, size_t query_len);
+int hostapd_dpp_configurator_add(struct hostapd_data *hapd, const char *cmd);
+int hostapd_dpp_configurator_remove(struct hostapd_data *hapd, const char *id);
 int hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd);
 int hostapd_dpp_pkex_remove(struct hostapd_data *hapd, const char *id);
 int hostapd_dpp_init(struct hostapd_data *hapd);
index 155728d4efa2f5503ab0eb9975d012481f85964f..e3068efb4e8335641e9a4b7204c93678be7fb501 100644 (file)
 #include "common.h"
 #include "common/ieee802_11_defs.h"
 #include "common/gas.h"
+#include "common/dpp.h"
+#include "common/wpa_ctrl.h"
 #include "utils/eloop.h"
 #include "hostapd.h"
 #include "ap_config.h"
 #include "ap_drv_ops.h"
+#include "dpp_hostapd.h"
 #include "sta_info.h"
 #include "gas_serv.h"
 
 
+#ifdef CONFIG_DPP
+static void gas_serv_write_dpp_adv_proto(struct wpabuf *buf)
+{
+       wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
+       wpabuf_put_u8(buf, 8); /* Length */
+       wpabuf_put_u8(buf, 0x7f);
+       wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
+       wpabuf_put_u8(buf, 5);
+       wpabuf_put_be24(buf, OUI_WFA);
+       wpabuf_put_u8(buf, DPP_OUI_TYPE);
+       wpabuf_put_u8(buf, 0x01);
+}
+#endif /* CONFIG_DPP */
+
+
 static void convert_to_protected_dual(struct wpabuf *msg)
 {
        u8 *categ = wpabuf_mhead_u8(msg);
@@ -1393,6 +1411,72 @@ static void gas_serv_req_local_processing(struct hostapd_data *hapd,
 }
 
 
+#ifdef CONFIG_DPP
+static void gas_serv_req_dpp_processing(struct hostapd_data *hapd,
+                                       const u8 *sa, u8 dialog_token,
+                                       int prot, struct wpabuf *buf)
+{
+       struct wpabuf *tx_buf;
+
+       if (wpabuf_len(buf) > hapd->conf->gas_frag_limit ||
+           hapd->conf->gas_comeback_delay) {
+               struct gas_dialog_info *di;
+               u16 comeback_delay = 1;
+
+               if (hapd->conf->gas_comeback_delay) {
+                       /* Testing - allow overriding of the delay value */
+                       comeback_delay = hapd->conf->gas_comeback_delay;
+               }
+
+               wpa_printf(MSG_DEBUG,
+                          "DPP: Too long response to fit in initial response - use GAS comeback");
+               di = gas_dialog_create(hapd, sa, dialog_token);
+               if (!di) {
+                       wpa_printf(MSG_INFO, "DPP: Could not create dialog for "
+                                  MACSTR " (dialog token %u)",
+                                  MAC2STR(sa), dialog_token);
+                       wpabuf_free(buf);
+                       tx_buf = gas_build_initial_resp(
+                               dialog_token, WLAN_STATUS_UNSPECIFIED_FAILURE,
+                               0, 10);
+                       if (tx_buf)
+                               gas_serv_write_dpp_adv_proto(tx_buf);
+               } else {
+                       di->prot = prot;
+                       di->sd_resp = buf;
+                       di->sd_resp_pos = 0;
+                       tx_buf = gas_build_initial_resp(
+                               dialog_token, WLAN_STATUS_SUCCESS,
+                               comeback_delay, 10);
+                       if (tx_buf)
+                               gas_serv_write_dpp_adv_proto(tx_buf);
+               }
+       } else {
+               wpa_printf(MSG_DEBUG,
+                          "DPP: GAS Initial response (no comeback)");
+               tx_buf = gas_build_initial_resp(
+                       dialog_token, WLAN_STATUS_SUCCESS, 0,
+                       10 + 2 + wpabuf_len(buf));
+               if (tx_buf) {
+                       gas_serv_write_dpp_adv_proto(tx_buf);
+                       wpabuf_put_le16(tx_buf, wpabuf_len(buf));
+                       wpabuf_put_buf(tx_buf, buf);
+                       wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT);
+               }
+               wpabuf_free(buf);
+       }
+       if (!tx_buf)
+               return;
+       if (prot)
+               convert_to_protected_dual(tx_buf);
+       hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
+                               wpabuf_head(tx_buf),
+                               wpabuf_len(tx_buf));
+       wpabuf_free(tx_buf);
+}
+#endif /* CONFIG_DPP */
+
+
 static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
                                        const u8 *sa,
                                        const u8 *data, size_t len, int prot,
@@ -1405,6 +1489,9 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
        u16 slen;
        struct anqp_query_info qi;
        const u8 *adv_proto;
+#ifdef CONFIG_DPP
+       int dpp = 0;
+#endif /* CONFIG_DPP */
 
        if (len < 1 + 2)
                return;
@@ -1432,6 +1519,15 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
        next = pos + slen;
        pos++; /* skip QueryRespLenLimit and PAME-BI */
 
+#ifdef CONFIG_DPP
+       if (slen == 8 && *pos == WLAN_EID_VENDOR_SPECIFIC &&
+           pos[1] == 5 && WPA_GET_BE24(&pos[2]) == OUI_WFA &&
+           pos[5] == DPP_OUI_TYPE && pos[6] == 0x01) {
+               wpa_printf(MSG_DEBUG, "DPP: Configuration Request");
+               dpp = 1;
+       } else
+#endif /* CONFIG_DPP */
+
        if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
                struct wpabuf *buf;
                wpa_msg(hapd->msg_ctx, MSG_DEBUG,
@@ -1471,6 +1567,18 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
                return;
        end = pos + slen;
 
+#ifdef CONFIG_DPP
+       if (dpp) {
+               struct wpabuf *msg;
+
+               msg = hostapd_dpp_gas_req_handler(hapd, sa, pos, slen);
+               if (!msg)
+                       return;
+               gas_serv_req_dpp_processing(hapd, sa, dialog_token, prot, msg);
+               return;
+       }
+#endif /* CONFIG_DPP */
+
        /* ANQP Query Request */
        while (pos < end) {
                u16 info_id, elen;
@@ -1558,6 +1666,18 @@ static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
                gas_serv_dialog_clear(dialog);
                return;
        }
+#ifdef CONFIG_DPP
+       if (dialog->dpp) {
+               tx_buf = gas_build_comeback_resp(dialog_token,
+                                                WLAN_STATUS_SUCCESS,
+                                                dialog->sd_frag_id, more, 0,
+                                                10 + frag_len);
+               if (tx_buf) {
+                       gas_serv_write_dpp_adv_proto(tx_buf);
+                       wpabuf_put_buf(tx_buf, buf);
+               }
+       } else
+#endif /* CONFIG_DPP */
        tx_buf = gas_anqp_build_comeback_resp_buf(dialog_token,
                                                  WLAN_STATUS_SUCCESS,
                                                  dialog->sd_frag_id,
@@ -1581,6 +1701,10 @@ static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
        } else {
                wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: All fragments of "
                        "SD response sent");
+#ifdef CONFIG_DPP
+               if (dialog->dpp)
+                       wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT);
+#endif /* CONFIG_DPP */
                gas_serv_dialog_clear(dialog);
                gas_serv_free_dialogs(hapd, sa);
        }
index 4af6ddafb9b6ede6a6f57699dd46c7f9936f8402..3a30298136c9609ea0cdcb789f818bc49dfe68b2 100644 (file)
@@ -71,6 +71,7 @@ struct gas_dialog_info {
        size_t sd_resp_pos; /* Offset in sd_resp */
        u8 sd_frag_id;
        int prot; /* whether Protected Dual of Public Action frame is used */
+       int dpp; /* whether this is a DPP Config Response */
 };
 
 struct hostapd_data;
index 9222628cc8b32b21ea8eb73798d5334e10c9b36f..794635f6657778f2f7a6f89c756424fe6be783ca 100644 (file)
@@ -322,6 +322,7 @@ struct hostapd_data {
 
 #ifdef CONFIG_DPP
        struct dl_list dpp_bootstrap; /* struct dpp_bootstrap_info */
+       struct dl_list dpp_configurator; /* struct dpp_configurator */
        int dpp_init_done;
        struct dpp_authentication *dpp_auth;
        u8 dpp_allowed_roles;