/* * wpa_supplicant - DPP * Copyright (c) 2017, Qualcomm Atheros, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #include "utils/includes.h" #include "utils/common.h" #include "common/dpp.h" #include "wpa_supplicant_i.h" #include "dpp_supplicant.h" static unsigned int wpas_dpp_next_id(struct wpa_supplicant *wpa_s) { struct dpp_bootstrap_info *bi; unsigned int max_id = 0; dl_list_for_each(bi, &wpa_s->dpp_bootstrap, struct dpp_bootstrap_info, list) { if (bi->id > max_id) max_id = bi->id; } return max_id + 1; } /** * wpas_dpp_qr_code - Parse and add DPP bootstrapping info from a QR Code * @wpa_s: Pointer to wpa_supplicant data * @cmd: DPP URI read from a QR Code * Returns: Identifier of the stored info or -1 on failure */ int wpas_dpp_qr_code(struct wpa_supplicant *wpa_s, const char *cmd) { struct dpp_bootstrap_info *bi; bi = dpp_parse_qr_code(cmd); if (!bi) return -1; bi->id = wpas_dpp_next_id(wpa_s); dl_list_add(&wpa_s->dpp_bootstrap, &bi->list); return bi->id; } static char * get_param(const char *cmd, const char *param) { const char *pos, *end; char *val; size_t len; pos = os_strstr(cmd, param); if (!pos) return NULL; pos += os_strlen(param); end = os_strchr(pos, ' '); if (end) len = end - pos; else len = os_strlen(pos); val = os_malloc(len + 1); if (!val) return NULL; os_memcpy(val, pos, len); val[len] = '\0'; return val; } int wpas_dpp_bootstrap_gen(struct wpa_supplicant *wpa_s, const char *cmd) { char *chan = NULL, *mac = NULL, *info = NULL, *pk = NULL, *curve = NULL; char *key = NULL; u8 *privkey = NULL; size_t privkey_len = 0; size_t len; int ret = -1; struct dpp_bootstrap_info *bi; bi = os_zalloc(sizeof(*bi)); if (!bi) goto fail; if (os_strstr(cmd, "type=qrcode")) bi->type = DPP_BOOTSTRAP_QR_CODE; else goto fail; chan = get_param(cmd, " chan="); mac = get_param(cmd, " mac="); info = get_param(cmd, " info="); 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; } pk = dpp_keygen(bi, curve, privkey, privkey_len); if (!pk) goto fail; len = 4; /* "DPP:" */ if (chan) { if (dpp_parse_uri_chan_list(bi, chan) < 0) goto fail; len += 3 + os_strlen(chan); /* C:...; */ } if (mac) { if (dpp_parse_uri_mac(bi, mac) < 0) goto fail; len += 3 + os_strlen(mac); /* M:...; */ } if (info) { if (dpp_parse_uri_info(bi, info) < 0) goto fail; len += 3 + os_strlen(info); /* I:...; */ } len += 4 + os_strlen(pk); bi->uri = os_malloc(len + 1); if (!bi->uri) goto fail; os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%s%sK:%s;;", chan ? "C:" : "", chan ? chan : "", chan ? ";" : "", mac ? "M:" : "", mac ? mac : "", mac ? ";" : "", info ? "I:" : "", info ? info : "", info ? ";" : "", pk); bi->id = wpas_dpp_next_id(wpa_s); dl_list_add(&wpa_s->dpp_bootstrap, &bi->list); ret = bi->id; bi = NULL; fail: os_free(curve); os_free(pk); os_free(chan); os_free(mac); os_free(info); str_clear_free(key); bin_clear_free(privkey, privkey_len); dpp_bootstrap_info_free(bi); return ret; } static struct dpp_bootstrap_info * dpp_bootstrap_get_id(struct wpa_supplicant *wpa_s, unsigned int id) { struct dpp_bootstrap_info *bi; dl_list_for_each(bi, &wpa_s->dpp_bootstrap, struct dpp_bootstrap_info, list) { if (bi->id == id) return bi; } return NULL; } static int dpp_bootstrap_del(struct wpa_supplicant *wpa_s, unsigned int id) { struct dpp_bootstrap_info *bi, *tmp; int found = 0; dl_list_for_each_safe(bi, tmp, &wpa_s->dpp_bootstrap, struct dpp_bootstrap_info, list) { if (id && bi->id != id) continue; found = 1; dl_list_del(&bi->list); dpp_bootstrap_info_free(bi); } if (id == 0) return 0; /* flush succeeds regardless of entries found */ return found ? 0 : -1; } int wpas_dpp_bootstrap_remove(struct wpa_supplicant *wpa_s, 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_bootstrap_del(wpa_s, id_val); } const char * wpas_dpp_bootstrap_get_uri(struct wpa_supplicant *wpa_s, unsigned int id) { struct dpp_bootstrap_info *bi; bi = dpp_bootstrap_get_id(wpa_s, id); if (!bi) return NULL; return bi->uri; } int wpas_dpp_init(struct wpa_supplicant *wpa_s) { dl_list_init(&wpa_s->dpp_bootstrap); wpa_s->dpp_init_done = 1; return 0; } void wpas_dpp_deinit(struct wpa_supplicant *wpa_s) { if (!wpa_s->dpp_init_done) return; dpp_bootstrap_del(wpa_s, 0); }