blob: 4d2b71ad8612ff1de5caabc96220c38159b5a120 [file] [log] [blame]
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001/*
2 * hostapd / DPP integration
3 * Copyright (c) 2017, Qualcomm Atheros, Inc.
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9#include "utils/includes.h"
10
11#include "utils/common.h"
12#include "utils/eloop.h"
13#include "common/dpp.h"
14#include "common/gas.h"
15#include "common/wpa_ctrl.h"
16#include "hostapd.h"
17#include "ap_drv_ops.h"
18#include "gas_query_ap.h"
19#include "wpa_auth.h"
20#include "dpp_hostapd.h"
21
22
Roshan Pius3a1667e2018-07-03 15:17:14 -070023static void hostapd_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070024static void hostapd_dpp_auth_success(struct hostapd_data *hapd, int initiator);
Roshan Pius3a1667e2018-07-03 15:17:14 -070025static void hostapd_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx);
26static int hostapd_dpp_auth_init_next(struct hostapd_data *hapd);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070027
28static const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
29
30
31static struct dpp_configurator *
32hostapd_dpp_configurator_get_id(struct hostapd_data *hapd, unsigned int id)
33{
34 struct dpp_configurator *conf;
35
Roshan Pius3a1667e2018-07-03 15:17:14 -070036 dl_list_for_each(conf, &hapd->iface->interfaces->dpp_configurator,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070037 struct dpp_configurator, list) {
38 if (conf->id == id)
39 return conf;
40 }
41 return NULL;
42}
43
44
45static unsigned int hapd_dpp_next_id(struct hostapd_data *hapd)
46{
47 struct dpp_bootstrap_info *bi;
48 unsigned int max_id = 0;
49
Roshan Pius3a1667e2018-07-03 15:17:14 -070050 dl_list_for_each(bi, &hapd->iface->interfaces->dpp_bootstrap,
51 struct dpp_bootstrap_info, list) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070052 if (bi->id > max_id)
53 max_id = bi->id;
54 }
55 return max_id + 1;
56}
57
58
59/**
60 * hostapd_dpp_qr_code - Parse and add DPP bootstrapping info from a QR Code
61 * @hapd: Pointer to hostapd_data
62 * @cmd: DPP URI read from a QR Code
63 * Returns: Identifier of the stored info or -1 on failure
64 */
65int hostapd_dpp_qr_code(struct hostapd_data *hapd, const char *cmd)
66{
67 struct dpp_bootstrap_info *bi;
68 struct dpp_authentication *auth = hapd->dpp_auth;
69
70 bi = dpp_parse_qr_code(cmd);
71 if (!bi)
72 return -1;
73
74 bi->id = hapd_dpp_next_id(hapd);
Roshan Pius3a1667e2018-07-03 15:17:14 -070075 dl_list_add(&hapd->iface->interfaces->dpp_bootstrap, &bi->list);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070076
77 if (auth && auth->response_pending &&
78 dpp_notify_new_qr_code(auth, bi) == 1) {
79 wpa_printf(MSG_DEBUG,
80 "DPP: Sending out pending authentication response");
Roshan Pius3a1667e2018-07-03 15:17:14 -070081 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
82 " freq=%u type=%d",
83 MAC2STR(auth->peer_mac_addr), auth->curr_freq,
84 DPP_PA_AUTHENTICATION_RESP);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070085 hostapd_drv_send_action(hapd, auth->curr_freq, 0,
86 auth->peer_mac_addr,
87 wpabuf_head(hapd->dpp_auth->resp_msg),
88 wpabuf_len(hapd->dpp_auth->resp_msg));
89 }
90
91 return bi->id;
92}
93
94
95static char * get_param(const char *cmd, const char *param)
96{
97 const char *pos, *end;
98 char *val;
99 size_t len;
100
101 pos = os_strstr(cmd, param);
102 if (!pos)
103 return NULL;
104
105 pos += os_strlen(param);
106 end = os_strchr(pos, ' ');
107 if (end)
108 len = end - pos;
109 else
110 len = os_strlen(pos);
111 val = os_malloc(len + 1);
112 if (!val)
113 return NULL;
114 os_memcpy(val, pos, len);
115 val[len] = '\0';
116 return val;
117}
118
119
120int hostapd_dpp_bootstrap_gen(struct hostapd_data *hapd, const char *cmd)
121{
122 char *chan = NULL, *mac = NULL, *info = NULL, *pk = NULL, *curve = NULL;
123 char *key = NULL;
124 u8 *privkey = NULL;
125 size_t privkey_len = 0;
126 size_t len;
127 int ret = -1;
128 struct dpp_bootstrap_info *bi;
129
130 bi = os_zalloc(sizeof(*bi));
131 if (!bi)
132 goto fail;
133
134 if (os_strstr(cmd, "type=qrcode"))
135 bi->type = DPP_BOOTSTRAP_QR_CODE;
136 else if (os_strstr(cmd, "type=pkex"))
137 bi->type = DPP_BOOTSTRAP_PKEX;
138 else
139 goto fail;
140
141 chan = get_param(cmd, " chan=");
142 mac = get_param(cmd, " mac=");
143 info = get_param(cmd, " info=");
144 curve = get_param(cmd, " curve=");
145 key = get_param(cmd, " key=");
146
147 if (key) {
148 privkey_len = os_strlen(key) / 2;
149 privkey = os_malloc(privkey_len);
150 if (!privkey ||
151 hexstr2bin(key, privkey, privkey_len) < 0)
152 goto fail;
153 }
154
155 pk = dpp_keygen(bi, curve, privkey, privkey_len);
156 if (!pk)
157 goto fail;
158
159 len = 4; /* "DPP:" */
160 if (chan) {
161 if (dpp_parse_uri_chan_list(bi, chan) < 0)
162 goto fail;
163 len += 3 + os_strlen(chan); /* C:...; */
164 }
165 if (mac) {
166 if (dpp_parse_uri_mac(bi, mac) < 0)
167 goto fail;
168 len += 3 + os_strlen(mac); /* M:...; */
169 }
170 if (info) {
171 if (dpp_parse_uri_info(bi, info) < 0)
172 goto fail;
173 len += 3 + os_strlen(info); /* I:...; */
174 }
175 len += 4 + os_strlen(pk);
176 bi->uri = os_malloc(len + 1);
177 if (!bi->uri)
178 goto fail;
179 os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%s%sK:%s;;",
180 chan ? "C:" : "", chan ? chan : "", chan ? ";" : "",
181 mac ? "M:" : "", mac ? mac : "", mac ? ";" : "",
182 info ? "I:" : "", info ? info : "", info ? ";" : "",
183 pk);
184 bi->id = hapd_dpp_next_id(hapd);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700185 dl_list_add(&hapd->iface->interfaces->dpp_bootstrap, &bi->list);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700186 ret = bi->id;
187 bi = NULL;
188fail:
189 os_free(curve);
190 os_free(pk);
191 os_free(chan);
192 os_free(mac);
193 os_free(info);
194 str_clear_free(key);
195 bin_clear_free(privkey, privkey_len);
196 dpp_bootstrap_info_free(bi);
197 return ret;
198}
199
200
201static struct dpp_bootstrap_info *
202dpp_bootstrap_get_id(struct hostapd_data *hapd, unsigned int id)
203{
204 struct dpp_bootstrap_info *bi;
205
Roshan Pius3a1667e2018-07-03 15:17:14 -0700206 dl_list_for_each(bi, &hapd->iface->interfaces->dpp_bootstrap,
207 struct dpp_bootstrap_info, list) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700208 if (bi->id == id)
209 return bi;
210 }
211 return NULL;
212}
213
214
Roshan Pius3a1667e2018-07-03 15:17:14 -0700215static int dpp_bootstrap_del(struct hapd_interfaces *ifaces, unsigned int id)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700216{
217 struct dpp_bootstrap_info *bi, *tmp;
218 int found = 0;
219
Roshan Pius3a1667e2018-07-03 15:17:14 -0700220 dl_list_for_each_safe(bi, tmp, &ifaces->dpp_bootstrap,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700221 struct dpp_bootstrap_info, list) {
222 if (id && bi->id != id)
223 continue;
224 found = 1;
225 dl_list_del(&bi->list);
226 dpp_bootstrap_info_free(bi);
227 }
228
229 if (id == 0)
230 return 0; /* flush succeeds regardless of entries found */
231 return found ? 0 : -1;
232}
233
234
235int hostapd_dpp_bootstrap_remove(struct hostapd_data *hapd, const char *id)
236{
237 unsigned int id_val;
238
239 if (os_strcmp(id, "*") == 0) {
240 id_val = 0;
241 } else {
242 id_val = atoi(id);
243 if (id_val == 0)
244 return -1;
245 }
246
Roshan Pius3a1667e2018-07-03 15:17:14 -0700247 return dpp_bootstrap_del(hapd->iface->interfaces, id_val);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700248}
249
250
251const char * hostapd_dpp_bootstrap_get_uri(struct hostapd_data *hapd,
252 unsigned int id)
253{
254 struct dpp_bootstrap_info *bi;
255
256 bi = dpp_bootstrap_get_id(hapd, id);
257 if (!bi)
258 return NULL;
259 return bi->uri;
260}
261
262
263int hostapd_dpp_bootstrap_info(struct hostapd_data *hapd, int id,
264 char *reply, int reply_size)
265{
266 struct dpp_bootstrap_info *bi;
267
268 bi = dpp_bootstrap_get_id(hapd, id);
269 if (!bi)
270 return -1;
271 return os_snprintf(reply, reply_size, "type=%s\n"
272 "mac_addr=" MACSTR "\n"
273 "info=%s\n"
274 "num_freq=%u\n"
275 "curve=%s\n",
276 dpp_bootstrap_type_txt(bi->type),
277 MAC2STR(bi->mac_addr),
278 bi->info ? bi->info : "",
279 bi->num_freq,
280 bi->curve->name);
281}
282
283
Roshan Pius3a1667e2018-07-03 15:17:14 -0700284static void hostapd_dpp_auth_resp_retry_timeout(void *eloop_ctx,
285 void *timeout_ctx)
286{
287 struct hostapd_data *hapd = eloop_ctx;
288 struct dpp_authentication *auth = hapd->dpp_auth;
289
290 if (!auth || !auth->resp_msg)
291 return;
292
293 wpa_printf(MSG_DEBUG,
294 "DPP: Retry Authentication Response after timeout");
295 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
296 " freq=%u type=%d",
297 MAC2STR(auth->peer_mac_addr), auth->curr_freq,
298 DPP_PA_AUTHENTICATION_RESP);
299 hostapd_drv_send_action(hapd, auth->curr_freq, 500, auth->peer_mac_addr,
300 wpabuf_head(auth->resp_msg),
301 wpabuf_len(auth->resp_msg));
302}
303
304
305static void hostapd_dpp_auth_resp_retry(struct hostapd_data *hapd)
306{
307 struct dpp_authentication *auth = hapd->dpp_auth;
308 unsigned int wait_time, max_tries;
309
310 if (!auth || !auth->resp_msg)
311 return;
312
313 if (hapd->dpp_resp_max_tries)
314 max_tries = hapd->dpp_resp_max_tries;
315 else
316 max_tries = 5;
317 auth->auth_resp_tries++;
318 if (auth->auth_resp_tries >= max_tries) {
319 wpa_printf(MSG_INFO,
320 "DPP: No confirm received from initiator - stopping exchange");
321 hostapd_drv_send_action_cancel_wait(hapd);
322 dpp_auth_deinit(hapd->dpp_auth);
323 hapd->dpp_auth = NULL;
324 return;
325 }
326
327 if (hapd->dpp_resp_retry_time)
328 wait_time = hapd->dpp_resp_retry_time;
329 else
330 wait_time = 1000;
331 wpa_printf(MSG_DEBUG,
332 "DPP: Schedule retransmission of Authentication Response frame in %u ms",
333 wait_time);
334 eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
335 eloop_register_timeout(wait_time / 1000,
336 (wait_time % 1000) * 1000,
337 hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
338}
339
340
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700341void hostapd_dpp_tx_status(struct hostapd_data *hapd, const u8 *dst,
342 const u8 *data, size_t data_len, int ok)
343{
Roshan Pius3a1667e2018-07-03 15:17:14 -0700344 struct dpp_authentication *auth = hapd->dpp_auth;
345
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700346 wpa_printf(MSG_DEBUG, "DPP: TX status: dst=" MACSTR " ok=%d",
347 MAC2STR(dst), ok);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700348 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR
349 " result=%s", MAC2STR(dst), ok ? "SUCCESS" : "FAILED");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700350
351 if (!hapd->dpp_auth) {
352 wpa_printf(MSG_DEBUG,
353 "DPP: Ignore TX status since there is no ongoing authentication exchange");
354 return;
355 }
356
357 if (hapd->dpp_auth->remove_on_tx_status) {
358 wpa_printf(MSG_DEBUG,
359 "DPP: Terminate authentication exchange due to an earlier error");
Roshan Pius3a1667e2018-07-03 15:17:14 -0700360 eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
361 eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout,
362 hapd, NULL);
363 eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd,
364 NULL);
365 hostapd_drv_send_action_cancel_wait(hapd);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700366 dpp_auth_deinit(hapd->dpp_auth);
367 hapd->dpp_auth = NULL;
368 return;
369 }
370
371 if (hapd->dpp_auth_ok_on_ack)
372 hostapd_dpp_auth_success(hapd, 1);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700373
374 if (!is_broadcast_ether_addr(dst) && !ok) {
375 wpa_printf(MSG_DEBUG,
376 "DPP: Unicast DPP Action frame was not ACKed");
377 if (auth->waiting_auth_resp) {
378 /* In case of DPP Authentication Request frame, move to
379 * the next channel immediately. */
380 hostapd_drv_send_action_cancel_wait(hapd);
381 hostapd_dpp_auth_init_next(hapd);
382 return;
383 }
384 if (auth->waiting_auth_conf) {
385 hostapd_dpp_auth_resp_retry(hapd);
386 return;
387 }
388 }
389
390 if (!is_broadcast_ether_addr(dst) && auth->waiting_auth_resp && ok) {
391 /* Allow timeout handling to stop iteration if no response is
392 * received from a peer that has ACKed a request. */
393 auth->auth_req_ack = 1;
394 }
395
396 if (!hapd->dpp_auth_ok_on_ack && hapd->dpp_auth->neg_freq > 0 &&
397 hapd->dpp_auth->curr_freq != hapd->dpp_auth->neg_freq) {
398 wpa_printf(MSG_DEBUG,
399 "DPP: Move from curr_freq %u MHz to neg_freq %u MHz for response",
400 hapd->dpp_auth->curr_freq,
401 hapd->dpp_auth->neg_freq);
402 hostapd_drv_send_action_cancel_wait(hapd);
403
404 if (hapd->dpp_auth->neg_freq !=
405 (unsigned int) hapd->iface->freq && hapd->iface->freq > 0) {
406 /* TODO: Listen operation on non-operating channel */
407 wpa_printf(MSG_INFO,
408 "DPP: Listen operation on non-operating channel (%d MHz) is not yet supported (operating channel: %d MHz)",
409 hapd->dpp_auth->neg_freq, hapd->iface->freq);
410 }
411 }
412
413 if (hapd->dpp_auth_ok_on_ack)
414 hapd->dpp_auth_ok_on_ack = 0;
415}
416
417
418static void hostapd_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx)
419{
420 struct hostapd_data *hapd = eloop_ctx;
421 struct dpp_authentication *auth = hapd->dpp_auth;
422 unsigned int freq;
423 struct os_reltime now, diff;
424 unsigned int wait_time, diff_ms;
425
426 if (!auth || !auth->waiting_auth_resp)
427 return;
428
429 wait_time = hapd->dpp_resp_wait_time ?
430 hapd->dpp_resp_wait_time : 2000;
431 os_get_reltime(&now);
432 os_reltime_sub(&now, &hapd->dpp_last_init, &diff);
433 diff_ms = diff.sec * 1000 + diff.usec / 1000;
434 wpa_printf(MSG_DEBUG,
435 "DPP: Reply wait timeout - wait_time=%u diff_ms=%u",
436 wait_time, diff_ms);
437
438 if (auth->auth_req_ack && diff_ms >= wait_time) {
439 /* Peer ACK'ed Authentication Request frame, but did not reply
440 * with Authentication Response frame within two seconds. */
441 wpa_printf(MSG_INFO,
442 "DPP: No response received from responder - stopping initiation attempt");
443 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_AUTH_INIT_FAILED);
444 hostapd_drv_send_action_cancel_wait(hapd);
445 hostapd_dpp_listen_stop(hapd);
446 dpp_auth_deinit(auth);
447 hapd->dpp_auth = NULL;
448 return;
449 }
450
451 if (diff_ms >= wait_time) {
452 /* Authentication Request frame was not ACK'ed and no reply
453 * was receiving within two seconds. */
454 wpa_printf(MSG_DEBUG,
455 "DPP: Continue Initiator channel iteration");
456 hostapd_drv_send_action_cancel_wait(hapd);
457 hostapd_dpp_listen_stop(hapd);
458 hostapd_dpp_auth_init_next(hapd);
459 return;
460 }
461
462 /* Driver did not support 2000 ms long wait_time with TX command, so
463 * schedule listen operation to continue waiting for the response.
464 *
465 * DPP listen operations continue until stopped, so simply schedule a
466 * new call to this function at the point when the two second reply
467 * wait has expired. */
468 wait_time -= diff_ms;
469
470 freq = auth->curr_freq;
471 if (auth->neg_freq > 0)
472 freq = auth->neg_freq;
473 wpa_printf(MSG_DEBUG,
474 "DPP: Continue reply wait on channel %u MHz for %u ms",
475 freq, wait_time);
476 hapd->dpp_in_response_listen = 1;
477
478 if (freq != (unsigned int) hapd->iface->freq && hapd->iface->freq > 0) {
479 /* TODO: Listen operation on non-operating channel */
480 wpa_printf(MSG_INFO,
481 "DPP: Listen operation on non-operating channel (%d MHz) is not yet supported (operating channel: %d MHz)",
482 freq, hapd->iface->freq);
483 }
484
485 eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000,
486 hostapd_dpp_reply_wait_timeout, hapd, NULL);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700487}
488
489
490static void hostapd_dpp_set_testing_options(struct hostapd_data *hapd,
491 struct dpp_authentication *auth)
492{
493#ifdef CONFIG_TESTING_OPTIONS
494 if (hapd->dpp_config_obj_override)
495 auth->config_obj_override =
496 os_strdup(hapd->dpp_config_obj_override);
497 if (hapd->dpp_discovery_override)
498 auth->discovery_override =
499 os_strdup(hapd->dpp_discovery_override);
500 if (hapd->dpp_groups_override)
501 auth->groups_override = os_strdup(hapd->dpp_groups_override);
502 auth->ignore_netaccesskey_mismatch =
503 hapd->dpp_ignore_netaccesskey_mismatch;
504#endif /* CONFIG_TESTING_OPTIONS */
505}
506
507
508static void hostapd_dpp_set_configurator(struct hostapd_data *hapd,
509 struct dpp_authentication *auth,
510 const char *cmd)
511{
512 const char *pos, *end;
513 struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL;
514 struct dpp_configurator *conf = NULL;
515 u8 ssid[32] = { "test" };
516 size_t ssid_len = 4;
517 char pass[64] = { };
518 size_t pass_len = 0;
519 u8 psk[PMK_LEN];
520 int psk_set = 0;
521
522 if (!cmd)
523 return;
524
525 wpa_printf(MSG_DEBUG, "DPP: Set configurator parameters: %s", cmd);
526 pos = os_strstr(cmd, " ssid=");
527 if (pos) {
528 pos += 6;
529 end = os_strchr(pos, ' ');
530 ssid_len = end ? (size_t) (end - pos) : os_strlen(pos);
531 ssid_len /= 2;
532 if (ssid_len > sizeof(ssid) ||
533 hexstr2bin(pos, ssid, ssid_len) < 0)
534 goto fail;
535 }
536
537 pos = os_strstr(cmd, " pass=");
538 if (pos) {
539 pos += 6;
540 end = os_strchr(pos, ' ');
541 pass_len = end ? (size_t) (end - pos) : os_strlen(pos);
542 pass_len /= 2;
543 if (pass_len > sizeof(pass) - 1 || pass_len < 8 ||
544 hexstr2bin(pos, (u8 *) pass, pass_len) < 0)
545 goto fail;
546 }
547
548 pos = os_strstr(cmd, " psk=");
549 if (pos) {
550 pos += 5;
551 if (hexstr2bin(pos, psk, PMK_LEN) < 0)
552 goto fail;
553 psk_set = 1;
554 }
555
556 if (os_strstr(cmd, " conf=sta-")) {
557 conf_sta = os_zalloc(sizeof(struct dpp_configuration));
558 if (!conf_sta)
559 goto fail;
560 os_memcpy(conf_sta->ssid, ssid, ssid_len);
561 conf_sta->ssid_len = ssid_len;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700562 if (os_strstr(cmd, " conf=sta-psk") ||
563 os_strstr(cmd, " conf=sta-sae") ||
564 os_strstr(cmd, " conf=sta-psk-sae")) {
565 if (os_strstr(cmd, " conf=sta-psk-sae"))
566 conf_sta->akm = DPP_AKM_PSK_SAE;
567 else if (os_strstr(cmd, " conf=sta-sae"))
568 conf_sta->akm = DPP_AKM_SAE;
569 else
570 conf_sta->akm = DPP_AKM_PSK;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700571 if (psk_set) {
572 os_memcpy(conf_sta->psk, psk, PMK_LEN);
573 } else {
574 conf_sta->passphrase = os_strdup(pass);
575 if (!conf_sta->passphrase)
576 goto fail;
577 }
578 } else if (os_strstr(cmd, " conf=sta-dpp")) {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700579 conf_sta->akm = DPP_AKM_DPP;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700580 } else {
581 goto fail;
582 }
583 }
584
585 if (os_strstr(cmd, " conf=ap-")) {
586 conf_ap = os_zalloc(sizeof(struct dpp_configuration));
587 if (!conf_ap)
588 goto fail;
589 os_memcpy(conf_ap->ssid, ssid, ssid_len);
590 conf_ap->ssid_len = ssid_len;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700591 if (os_strstr(cmd, " conf=ap-psk") ||
592 os_strstr(cmd, " conf=ap-sae") ||
593 os_strstr(cmd, " conf=ap-psk-sae")) {
594 if (os_strstr(cmd, " conf=ap-psk-sae"))
595 conf_ap->akm = DPP_AKM_PSK_SAE;
596 else if (os_strstr(cmd, " conf=ap-sae"))
597 conf_ap->akm = DPP_AKM_SAE;
598 else
599 conf_ap->akm = DPP_AKM_PSK;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700600 if (psk_set) {
601 os_memcpy(conf_ap->psk, psk, PMK_LEN);
602 } else {
603 conf_ap->passphrase = os_strdup(pass);
604 if (!conf_ap->passphrase)
605 goto fail;
606 }
607 } else if (os_strstr(cmd, " conf=ap-dpp")) {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700608 conf_ap->akm = DPP_AKM_DPP;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700609 } else {
610 goto fail;
611 }
612 }
613
614 pos = os_strstr(cmd, " expiry=");
615 if (pos) {
616 long int val;
617
618 pos += 8;
619 val = strtol(pos, NULL, 0);
620 if (val <= 0)
621 goto fail;
622 if (conf_sta)
623 conf_sta->netaccesskey_expiry = val;
624 if (conf_ap)
625 conf_ap->netaccesskey_expiry = val;
626 }
627
628 pos = os_strstr(cmd, " configurator=");
629 if (pos) {
630 auth->configurator = 1;
631 pos += 14;
632 conf = hostapd_dpp_configurator_get_id(hapd, atoi(pos));
633 if (!conf) {
634 wpa_printf(MSG_INFO,
635 "DPP: Could not find the specified configurator");
636 goto fail;
637 }
638 }
639 auth->conf_sta = conf_sta;
640 auth->conf_ap = conf_ap;
641 auth->conf = conf;
642 return;
643
644fail:
645 wpa_printf(MSG_DEBUG, "DPP: Failed to set configurator parameters");
646 dpp_configuration_free(conf_sta);
647 dpp_configuration_free(conf_ap);
648}
649
650
Roshan Pius3a1667e2018-07-03 15:17:14 -0700651static void hostapd_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx)
652{
653 struct hostapd_data *hapd = eloop_ctx;
654
655 if (!hapd->dpp_auth)
656 return;
657 wpa_printf(MSG_DEBUG, "DPP: Retry initiation after timeout");
658 hostapd_dpp_auth_init_next(hapd);
659}
660
661
662static int hostapd_dpp_auth_init_next(struct hostapd_data *hapd)
663{
664 struct dpp_authentication *auth = hapd->dpp_auth;
665 const u8 *dst;
666 unsigned int wait_time, max_wait_time, freq, max_tries, used;
667 struct os_reltime now, diff;
668
669 if (!auth)
670 return -1;
671
672 if (auth->freq_idx == 0)
673 os_get_reltime(&hapd->dpp_init_iter_start);
674
675 if (auth->freq_idx >= auth->num_freq) {
676 auth->num_freq_iters++;
677 if (hapd->dpp_init_max_tries)
678 max_tries = hapd->dpp_init_max_tries;
679 else
680 max_tries = 5;
681 if (auth->num_freq_iters >= max_tries || auth->auth_req_ack) {
682 wpa_printf(MSG_INFO,
683 "DPP: No response received from responder - stopping initiation attempt");
684 wpa_msg(hapd->msg_ctx, MSG_INFO,
685 DPP_EVENT_AUTH_INIT_FAILED);
686 eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout,
687 hapd, NULL);
688 hostapd_drv_send_action_cancel_wait(hapd);
689 dpp_auth_deinit(hapd->dpp_auth);
690 hapd->dpp_auth = NULL;
691 return -1;
692 }
693 auth->freq_idx = 0;
694 eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
695 if (hapd->dpp_init_retry_time)
696 wait_time = hapd->dpp_init_retry_time;
697 else
698 wait_time = 10000;
699 os_get_reltime(&now);
700 os_reltime_sub(&now, &hapd->dpp_init_iter_start, &diff);
701 used = diff.sec * 1000 + diff.usec / 1000;
702 if (used > wait_time)
703 wait_time = 0;
704 else
705 wait_time -= used;
706 wpa_printf(MSG_DEBUG, "DPP: Next init attempt in %u ms",
707 wait_time);
708 eloop_register_timeout(wait_time / 1000,
709 (wait_time % 1000) * 1000,
710 hostapd_dpp_init_timeout, hapd,
711 NULL);
712 return 0;
713 }
714 freq = auth->freq[auth->freq_idx++];
715 auth->curr_freq = freq;
716
717 if (is_zero_ether_addr(auth->peer_bi->mac_addr))
718 dst = broadcast;
719 else
720 dst = auth->peer_bi->mac_addr;
721 hapd->dpp_auth_ok_on_ack = 0;
722 eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
723 wait_time = 2000; /* TODO: hapd->max_remain_on_chan; */
724 max_wait_time = hapd->dpp_resp_wait_time ?
725 hapd->dpp_resp_wait_time : 2000;
726 if (wait_time > max_wait_time)
727 wait_time = max_wait_time;
728 wait_time += 10; /* give the driver some extra time to complete */
729 eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000,
730 hostapd_dpp_reply_wait_timeout, hapd, NULL);
731 wait_time -= 10;
732 if (auth->neg_freq > 0 && freq != auth->neg_freq) {
733 wpa_printf(MSG_DEBUG,
734 "DPP: Initiate on %u MHz and move to neg_freq %u MHz for response",
735 freq, auth->neg_freq);
736 }
737 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
738 " freq=%u type=%d",
739 MAC2STR(dst), freq, DPP_PA_AUTHENTICATION_REQ);
740 auth->auth_req_ack = 0;
741 os_get_reltime(&hapd->dpp_last_init);
742 return hostapd_drv_send_action(hapd, freq, wait_time,
743 dst,
744 wpabuf_head(hapd->dpp_auth->req_msg),
745 wpabuf_len(hapd->dpp_auth->req_msg));
746}
747
748
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700749int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd)
750{
751 const char *pos;
752 struct dpp_bootstrap_info *peer_bi, *own_bi = NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700753 u8 allowed_roles = DPP_CAPAB_CONFIGURATOR;
754 unsigned int neg_freq = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700755
756 pos = os_strstr(cmd, " peer=");
757 if (!pos)
758 return -1;
759 pos += 6;
760 peer_bi = dpp_bootstrap_get_id(hapd, atoi(pos));
761 if (!peer_bi) {
762 wpa_printf(MSG_INFO,
763 "DPP: Could not find bootstrapping info for the identified peer");
764 return -1;
765 }
766
767 pos = os_strstr(cmd, " own=");
768 if (pos) {
769 pos += 5;
770 own_bi = dpp_bootstrap_get_id(hapd, atoi(pos));
771 if (!own_bi) {
772 wpa_printf(MSG_INFO,
773 "DPP: Could not find bootstrapping info for the identified local entry");
774 return -1;
775 }
776
777 if (peer_bi->curve != own_bi->curve) {
778 wpa_printf(MSG_INFO,
779 "DPP: Mismatching curves in bootstrapping info (peer=%s own=%s)",
780 peer_bi->curve->name, own_bi->curve->name);
781 return -1;
782 }
783 }
784
785 pos = os_strstr(cmd, " role=");
786 if (pos) {
787 pos += 6;
788 if (os_strncmp(pos, "configurator", 12) == 0)
Roshan Pius3a1667e2018-07-03 15:17:14 -0700789 allowed_roles = DPP_CAPAB_CONFIGURATOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700790 else if (os_strncmp(pos, "enrollee", 8) == 0)
Roshan Pius3a1667e2018-07-03 15:17:14 -0700791 allowed_roles = DPP_CAPAB_ENROLLEE;
792 else if (os_strncmp(pos, "either", 6) == 0)
793 allowed_roles = DPP_CAPAB_CONFIGURATOR |
794 DPP_CAPAB_ENROLLEE;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700795 else
796 goto fail;
797 }
798
Roshan Pius3a1667e2018-07-03 15:17:14 -0700799 pos = os_strstr(cmd, " neg_freq=");
800 if (pos)
801 neg_freq = atoi(pos + 10);
802
803 if (hapd->dpp_auth) {
804 eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
805 eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout,
806 hapd, NULL);
807 eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd,
808 NULL);
809 hostapd_drv_send_action_cancel_wait(hapd);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700810 dpp_auth_deinit(hapd->dpp_auth);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700811 }
812
813 hapd->dpp_auth = dpp_auth_init(hapd->msg_ctx, peer_bi, own_bi,
814 allowed_roles, neg_freq,
815 hapd->iface->hw_features,
816 hapd->iface->num_hw_features);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700817 if (!hapd->dpp_auth)
818 goto fail;
819 hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth);
820 hostapd_dpp_set_configurator(hapd, hapd->dpp_auth, cmd);
821
Roshan Pius3a1667e2018-07-03 15:17:14 -0700822 hapd->dpp_auth->neg_freq = neg_freq;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700823
Roshan Pius3a1667e2018-07-03 15:17:14 -0700824 if (!is_zero_ether_addr(peer_bi->mac_addr))
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700825 os_memcpy(hapd->dpp_auth->peer_mac_addr, peer_bi->mac_addr,
826 ETH_ALEN);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700827
Roshan Pius3a1667e2018-07-03 15:17:14 -0700828 return hostapd_dpp_auth_init_next(hapd);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700829fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700830 return -1;
831}
832
833
Roshan Pius3a1667e2018-07-03 15:17:14 -0700834int hostapd_dpp_listen(struct hostapd_data *hapd, const char *cmd)
835{
836 int freq;
837
838 freq = atoi(cmd);
839 if (freq <= 0)
840 return -1;
841
842 if (os_strstr(cmd, " role=configurator"))
843 hapd->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR;
844 else if (os_strstr(cmd, " role=enrollee"))
845 hapd->dpp_allowed_roles = DPP_CAPAB_ENROLLEE;
846 else
847 hapd->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR |
848 DPP_CAPAB_ENROLLEE;
849 hapd->dpp_qr_mutual = os_strstr(cmd, " qr=mutual") != NULL;
850
851 if (freq != hapd->iface->freq && hapd->iface->freq > 0) {
852 /* TODO: Listen operation on non-operating channel */
853 wpa_printf(MSG_INFO,
854 "DPP: Listen operation on non-operating channel (%d MHz) is not yet supported (operating channel: %d MHz)",
855 freq, hapd->iface->freq);
856 return -1;
857 }
858
859 return 0;
860}
861
862
863void hostapd_dpp_listen_stop(struct hostapd_data *hapd)
864{
865 /* TODO: Stop listen operation on non-operating channel */
866}
867
868
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700869static void hostapd_dpp_rx_auth_req(struct hostapd_data *hapd, const u8 *src,
870 const u8 *hdr, const u8 *buf, size_t len,
871 unsigned int freq)
872{
Roshan Pius3a1667e2018-07-03 15:17:14 -0700873 const u8 *r_bootstrap, *i_bootstrap;
874 u16 r_bootstrap_len, i_bootstrap_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700875 struct dpp_bootstrap_info *bi, *own_bi = NULL, *peer_bi = NULL;
876
877 wpa_printf(MSG_DEBUG, "DPP: Authentication Request from " MACSTR,
878 MAC2STR(src));
879
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700880 r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
881 &r_bootstrap_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700882 if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
883 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
884 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700885 return;
886 }
887 wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
888 r_bootstrap, r_bootstrap_len);
889
890 i_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
891 &i_bootstrap_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700892 if (!i_bootstrap || i_bootstrap_len != SHA256_MAC_LEN) {
893 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
894 "Missing or invalid required Initiator Bootstrapping Key Hash attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700895 return;
896 }
897 wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Bootstrapping Key Hash",
898 i_bootstrap, i_bootstrap_len);
899
900 /* Try to find own and peer bootstrapping key matches based on the
901 * received hash values */
Roshan Pius3a1667e2018-07-03 15:17:14 -0700902 dl_list_for_each(bi, &hapd->iface->interfaces->dpp_bootstrap,
903 struct dpp_bootstrap_info, list) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700904 if (!own_bi && bi->own &&
905 os_memcmp(bi->pubkey_hash, r_bootstrap,
906 SHA256_MAC_LEN) == 0) {
907 wpa_printf(MSG_DEBUG,
908 "DPP: Found matching own bootstrapping information");
909 own_bi = bi;
910 }
911
912 if (!peer_bi && !bi->own &&
913 os_memcmp(bi->pubkey_hash, i_bootstrap,
914 SHA256_MAC_LEN) == 0) {
915 wpa_printf(MSG_DEBUG,
916 "DPP: Found matching peer bootstrapping information");
917 peer_bi = bi;
918 }
919
920 if (own_bi && peer_bi)
921 break;
922 }
923
924 if (!own_bi) {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700925 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
926 "No matching own bootstrapping key found - ignore message");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700927 return;
928 }
929
930 if (hapd->dpp_auth) {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700931 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
932 "Already in DPP authentication exchange - ignore new one");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700933 return;
934 }
935
936 hapd->dpp_auth_ok_on_ack = 0;
937 hapd->dpp_auth = dpp_auth_req_rx(hapd->msg_ctx, hapd->dpp_allowed_roles,
938 hapd->dpp_qr_mutual,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700939 peer_bi, own_bi, freq, hdr, buf, len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700940 if (!hapd->dpp_auth) {
941 wpa_printf(MSG_DEBUG, "DPP: No response generated");
942 return;
943 }
944 hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth);
945 hostapd_dpp_set_configurator(hapd, hapd->dpp_auth,
946 hapd->dpp_configurator_params);
947 os_memcpy(hapd->dpp_auth->peer_mac_addr, src, ETH_ALEN);
948
Roshan Pius3a1667e2018-07-03 15:17:14 -0700949 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
950 " freq=%u type=%d",
951 MAC2STR(src), hapd->dpp_auth->curr_freq,
952 DPP_PA_AUTHENTICATION_RESP);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700953 hostapd_drv_send_action(hapd, hapd->dpp_auth->curr_freq, 0,
954 src, wpabuf_head(hapd->dpp_auth->resp_msg),
955 wpabuf_len(hapd->dpp_auth->resp_msg));
956}
957
958
Roshan Pius3a1667e2018-07-03 15:17:14 -0700959static void hostapd_dpp_handle_config_obj(struct hostapd_data *hapd,
960 struct dpp_authentication *auth)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700961{
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700962 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700963 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_AKM "%s",
964 dpp_akm_str(auth->akm));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700965 if (auth->ssid_len)
966 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_SSID "%s",
967 wpa_ssid_txt(auth->ssid, auth->ssid_len));
968 if (auth->connector) {
969 /* TODO: Save the Connector and consider using a command
970 * to fetch the value instead of sending an event with
971 * it. The Connector could end up being larger than what
972 * most clients are ready to receive as an event
973 * message. */
974 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONNECTOR "%s",
975 auth->connector);
976 } else if (auth->passphrase[0]) {
977 char hex[64 * 2 + 1];
978
979 wpa_snprintf_hex(hex, sizeof(hex),
980 (const u8 *) auth->passphrase,
981 os_strlen(auth->passphrase));
982 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_PASS "%s",
983 hex);
984 } else if (auth->psk_set) {
985 char hex[PMK_LEN * 2 + 1];
986
987 wpa_snprintf_hex(hex, sizeof(hex), auth->psk, PMK_LEN);
988 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_PSK "%s",
989 hex);
990 }
991 if (auth->c_sign_key) {
992 char *hex;
993 size_t hexlen;
994
995 hexlen = 2 * wpabuf_len(auth->c_sign_key) + 1;
996 hex = os_malloc(hexlen);
997 if (hex) {
998 wpa_snprintf_hex(hex, hexlen,
999 wpabuf_head(auth->c_sign_key),
1000 wpabuf_len(auth->c_sign_key));
1001 wpa_msg(hapd->msg_ctx, MSG_INFO,
1002 DPP_EVENT_C_SIGN_KEY "%s", hex);
1003 os_free(hex);
1004 }
1005 }
1006 if (auth->net_access_key) {
1007 char *hex;
1008 size_t hexlen;
1009
1010 hexlen = 2 * wpabuf_len(auth->net_access_key) + 1;
1011 hex = os_malloc(hexlen);
1012 if (hex) {
1013 wpa_snprintf_hex(hex, hexlen,
1014 wpabuf_head(auth->net_access_key),
1015 wpabuf_len(auth->net_access_key));
1016 if (auth->net_access_key_expiry)
1017 wpa_msg(hapd->msg_ctx, MSG_INFO,
1018 DPP_EVENT_NET_ACCESS_KEY "%s %lu", hex,
1019 (unsigned long)
1020 auth->net_access_key_expiry);
1021 else
1022 wpa_msg(hapd->msg_ctx, MSG_INFO,
1023 DPP_EVENT_NET_ACCESS_KEY "%s", hex);
1024 os_free(hex);
1025 }
1026 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001027}
1028
1029
1030static void hostapd_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
1031 enum gas_query_ap_result result,
1032 const struct wpabuf *adv_proto,
1033 const struct wpabuf *resp, u16 status_code)
1034{
1035 struct hostapd_data *hapd = ctx;
1036 const u8 *pos;
1037 struct dpp_authentication *auth = hapd->dpp_auth;
1038
1039 if (!auth || !auth->auth_success) {
1040 wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
1041 return;
1042 }
1043 if (!resp || status_code != WLAN_STATUS_SUCCESS) {
1044 wpa_printf(MSG_DEBUG, "DPP: GAS query did not succeed");
1045 goto fail;
1046 }
1047
1048 wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Response adv_proto",
1049 adv_proto);
1050 wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Response (GAS response)",
1051 resp);
1052
1053 if (wpabuf_len(adv_proto) != 10 ||
1054 !(pos = wpabuf_head(adv_proto)) ||
1055 pos[0] != WLAN_EID_ADV_PROTO ||
1056 pos[1] != 8 ||
1057 pos[3] != WLAN_EID_VENDOR_SPECIFIC ||
1058 pos[4] != 5 ||
1059 WPA_GET_BE24(&pos[5]) != OUI_WFA ||
1060 pos[8] != 0x1a ||
1061 pos[9] != 1) {
1062 wpa_printf(MSG_DEBUG,
1063 "DPP: Not a DPP Advertisement Protocol ID");
1064 goto fail;
1065 }
1066
1067 if (dpp_conf_resp_rx(auth, resp) < 0) {
1068 wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
1069 goto fail;
1070 }
1071
1072 hostapd_dpp_handle_config_obj(hapd, auth);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001073 dpp_auth_deinit(hapd->dpp_auth);
1074 hapd->dpp_auth = NULL;
1075 return;
1076
1077fail:
1078 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
1079 dpp_auth_deinit(hapd->dpp_auth);
1080 hapd->dpp_auth = NULL;
1081}
1082
1083
1084static void hostapd_dpp_start_gas_client(struct hostapd_data *hapd)
1085{
1086 struct dpp_authentication *auth = hapd->dpp_auth;
1087 struct wpabuf *buf, *conf_req;
1088 char json[100];
1089 int res;
1090 int netrole_ap = 1;
1091
1092 os_snprintf(json, sizeof(json),
1093 "{\"name\":\"Test\","
1094 "\"wi-fi_tech\":\"infra\","
1095 "\"netRole\":\"%s\"}",
1096 netrole_ap ? "ap" : "sta");
1097 wpa_printf(MSG_DEBUG, "DPP: GAS Config Attributes: %s", json);
1098
1099 conf_req = dpp_build_conf_req(auth, json);
1100 if (!conf_req) {
1101 wpa_printf(MSG_DEBUG,
1102 "DPP: No configuration request data available");
1103 return;
1104 }
1105
1106 buf = gas_build_initial_req(0, 10 + 2 + wpabuf_len(conf_req));
1107 if (!buf) {
1108 wpabuf_free(conf_req);
1109 return;
1110 }
1111
1112 /* Advertisement Protocol IE */
1113 wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
1114 wpabuf_put_u8(buf, 8); /* Length */
1115 wpabuf_put_u8(buf, 0x7f);
1116 wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
1117 wpabuf_put_u8(buf, 5);
1118 wpabuf_put_be24(buf, OUI_WFA);
1119 wpabuf_put_u8(buf, DPP_OUI_TYPE);
1120 wpabuf_put_u8(buf, 0x01);
1121
1122 /* GAS Query */
1123 wpabuf_put_le16(buf, wpabuf_len(conf_req));
1124 wpabuf_put_buf(buf, conf_req);
1125 wpabuf_free(conf_req);
1126
1127 wpa_printf(MSG_DEBUG, "DPP: GAS request to " MACSTR " (freq %u MHz)",
1128 MAC2STR(auth->peer_mac_addr), auth->curr_freq);
1129
1130 res = gas_query_ap_req(hapd->gas, auth->peer_mac_addr, auth->curr_freq,
1131 buf, hostapd_dpp_gas_resp_cb, hapd);
1132 if (res < 0) {
1133 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
1134 "GAS: Failed to send Query Request");
1135 wpabuf_free(buf);
1136 } else {
1137 wpa_printf(MSG_DEBUG,
1138 "DPP: GAS query started with dialog token %u", res);
1139 }
1140}
1141
1142
1143static void hostapd_dpp_auth_success(struct hostapd_data *hapd, int initiator)
1144{
1145 wpa_printf(MSG_DEBUG, "DPP: Authentication succeeded");
1146 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_AUTH_SUCCESS "init=%d",
1147 initiator);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001148#ifdef CONFIG_TESTING_OPTIONS
1149 if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) {
1150 wpa_printf(MSG_INFO,
1151 "DPP: TESTING - stop at Authentication Confirm");
1152 if (hapd->dpp_auth->configurator) {
1153 /* Prevent GAS response */
1154 hapd->dpp_auth->auth_success = 0;
1155 }
1156 return;
1157 }
1158#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001159
1160 if (!hapd->dpp_auth->configurator)
1161 hostapd_dpp_start_gas_client(hapd);
1162}
1163
1164
1165static void hostapd_dpp_rx_auth_resp(struct hostapd_data *hapd, const u8 *src,
Roshan Pius3a1667e2018-07-03 15:17:14 -07001166 const u8 *hdr, const u8 *buf, size_t len,
1167 unsigned int freq)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001168{
1169 struct dpp_authentication *auth = hapd->dpp_auth;
1170 struct wpabuf *msg;
1171
1172 wpa_printf(MSG_DEBUG, "DPP: Authentication Response from " MACSTR,
1173 MAC2STR(src));
1174
1175 if (!auth) {
1176 wpa_printf(MSG_DEBUG,
1177 "DPP: No DPP Authentication in progress - drop");
1178 return;
1179 }
1180
1181 if (!is_zero_ether_addr(auth->peer_mac_addr) &&
1182 os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
1183 wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
1184 MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
1185 return;
1186 }
1187
Roshan Pius3a1667e2018-07-03 15:17:14 -07001188 eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
1189
1190 if (auth->curr_freq != freq && auth->neg_freq == freq) {
1191 wpa_printf(MSG_DEBUG,
1192 "DPP: Responder accepted request for different negotiation channel");
1193 auth->curr_freq = freq;
1194 }
1195
1196 eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001197 msg = dpp_auth_resp_rx(auth, hdr, buf, len);
1198 if (!msg) {
1199 if (auth->auth_resp_status == DPP_STATUS_RESPONSE_PENDING) {
1200 wpa_printf(MSG_DEBUG, "DPP: Wait for full response");
1201 return;
1202 }
1203 wpa_printf(MSG_DEBUG, "DPP: No confirm generated");
1204 return;
1205 }
1206 os_memcpy(auth->peer_mac_addr, src, ETH_ALEN);
1207
Roshan Pius3a1667e2018-07-03 15:17:14 -07001208 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
1209 " freq=%u type=%d", MAC2STR(src), auth->curr_freq,
1210 DPP_PA_AUTHENTICATION_CONF);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001211 hostapd_drv_send_action(hapd, auth->curr_freq, 0, src,
1212 wpabuf_head(msg), wpabuf_len(msg));
1213 wpabuf_free(msg);
1214 hapd->dpp_auth_ok_on_ack = 1;
1215}
1216
1217
1218static void hostapd_dpp_rx_auth_conf(struct hostapd_data *hapd, const u8 *src,
1219 const u8 *hdr, const u8 *buf, size_t len)
1220{
1221 struct dpp_authentication *auth = hapd->dpp_auth;
1222
1223 wpa_printf(MSG_DEBUG, "DPP: Authentication Confirmation from " MACSTR,
1224 MAC2STR(src));
1225
1226 if (!auth) {
1227 wpa_printf(MSG_DEBUG,
1228 "DPP: No DPP Authentication in progress - drop");
1229 return;
1230 }
1231
1232 if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
1233 wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
1234 MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
1235 return;
1236 }
1237
1238 if (dpp_auth_conf_rx(auth, hdr, buf, len) < 0) {
1239 wpa_printf(MSG_DEBUG, "DPP: Authentication failed");
1240 return;
1241 }
1242
1243 hostapd_dpp_auth_success(hapd, 0);
1244}
1245
1246
Roshan Pius3a1667e2018-07-03 15:17:14 -07001247static void hostapd_dpp_send_peer_disc_resp(struct hostapd_data *hapd,
1248 const u8 *src, unsigned int freq,
1249 u8 trans_id,
1250 enum dpp_status_error status)
1251{
1252 struct wpabuf *msg;
1253
1254 msg = dpp_alloc_msg(DPP_PA_PEER_DISCOVERY_RESP,
1255 5 + 5 + 4 + os_strlen(hapd->conf->dpp_connector));
1256 if (!msg)
1257 return;
1258
1259#ifdef CONFIG_TESTING_OPTIONS
1260 if (dpp_test == DPP_TEST_NO_TRANSACTION_ID_PEER_DISC_RESP) {
1261 wpa_printf(MSG_INFO, "DPP: TESTING - no Transaction ID");
1262 goto skip_trans_id;
1263 }
1264 if (dpp_test == DPP_TEST_INVALID_TRANSACTION_ID_PEER_DISC_RESP) {
1265 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Transaction ID");
1266 trans_id ^= 0x01;
1267 }
1268#endif /* CONFIG_TESTING_OPTIONS */
1269
1270 /* Transaction ID */
1271 wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID);
1272 wpabuf_put_le16(msg, 1);
1273 wpabuf_put_u8(msg, trans_id);
1274
1275#ifdef CONFIG_TESTING_OPTIONS
1276skip_trans_id:
1277 if (dpp_test == DPP_TEST_NO_STATUS_PEER_DISC_RESP) {
1278 wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
1279 goto skip_status;
1280 }
1281 if (dpp_test == DPP_TEST_INVALID_STATUS_PEER_DISC_RESP) {
1282 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
1283 status = 254;
1284 }
1285#endif /* CONFIG_TESTING_OPTIONS */
1286
1287 /* DPP Status */
1288 wpabuf_put_le16(msg, DPP_ATTR_STATUS);
1289 wpabuf_put_le16(msg, 1);
1290 wpabuf_put_u8(msg, status);
1291
1292#ifdef CONFIG_TESTING_OPTIONS
1293skip_status:
1294 if (dpp_test == DPP_TEST_NO_CONNECTOR_PEER_DISC_RESP) {
1295 wpa_printf(MSG_INFO, "DPP: TESTING - no Connector");
1296 goto skip_connector;
1297 }
1298 if (status == DPP_STATUS_OK &&
1299 dpp_test == DPP_TEST_INVALID_CONNECTOR_PEER_DISC_RESP) {
1300 char *connector;
1301
1302 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Connector");
1303 connector = dpp_corrupt_connector_signature(
1304 hapd->conf->dpp_connector);
1305 if (!connector) {
1306 wpabuf_free(msg);
1307 return;
1308 }
1309 wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
1310 wpabuf_put_le16(msg, os_strlen(connector));
1311 wpabuf_put_str(msg, connector);
1312 os_free(connector);
1313 goto skip_connector;
1314 }
1315#endif /* CONFIG_TESTING_OPTIONS */
1316
1317 /* DPP Connector */
1318 if (status == DPP_STATUS_OK) {
1319 wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
1320 wpabuf_put_le16(msg, os_strlen(hapd->conf->dpp_connector));
1321 wpabuf_put_str(msg, hapd->conf->dpp_connector);
1322 }
1323
1324#ifdef CONFIG_TESTING_OPTIONS
1325skip_connector:
1326#endif /* CONFIG_TESTING_OPTIONS */
1327
1328 wpa_printf(MSG_DEBUG, "DPP: Send Peer Discovery Response to " MACSTR
1329 " status=%d", MAC2STR(src), status);
1330 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
1331 " freq=%u type=%d status=%d", MAC2STR(src), freq,
1332 DPP_PA_PEER_DISCOVERY_RESP, status);
1333 hostapd_drv_send_action(hapd, freq, 0, src,
1334 wpabuf_head(msg), wpabuf_len(msg));
1335 wpabuf_free(msg);
1336}
1337
1338
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001339static void hostapd_dpp_rx_peer_disc_req(struct hostapd_data *hapd,
1340 const u8 *src,
1341 const u8 *buf, size_t len,
1342 unsigned int freq)
1343{
1344 const u8 *connector, *trans_id;
1345 u16 connector_len, trans_id_len;
1346 struct os_time now;
1347 struct dpp_introduction intro;
1348 os_time_t expire;
1349 int expiration;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001350 enum dpp_status_error res;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001351
1352 wpa_printf(MSG_DEBUG, "DPP: Peer Discovery Request from " MACSTR,
1353 MAC2STR(src));
1354 if (!hapd->wpa_auth ||
1355 !(hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) ||
1356 !(hapd->conf->wpa & WPA_PROTO_RSN)) {
1357 wpa_printf(MSG_DEBUG, "DPP: DPP AKM not in use");
1358 return;
1359 }
1360
1361 if (!hapd->conf->dpp_connector || !hapd->conf->dpp_netaccesskey ||
1362 !hapd->conf->dpp_csign) {
1363 wpa_printf(MSG_DEBUG, "DPP: No own Connector/keys set");
1364 return;
1365 }
1366
1367 os_get_time(&now);
1368
1369 if (hapd->conf->dpp_netaccesskey_expiry &&
Roshan Pius3a1667e2018-07-03 15:17:14 -07001370 (os_time_t) hapd->conf->dpp_netaccesskey_expiry < now.sec) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001371 wpa_printf(MSG_INFO, "DPP: Own netAccessKey expired");
1372 return;
1373 }
1374
1375 trans_id = dpp_get_attr(buf, len, DPP_ATTR_TRANSACTION_ID,
1376 &trans_id_len);
1377 if (!trans_id || trans_id_len != 1) {
1378 wpa_printf(MSG_DEBUG,
1379 "DPP: Peer did not include Transaction ID");
1380 return;
1381 }
1382
1383 connector = dpp_get_attr(buf, len, DPP_ATTR_CONNECTOR, &connector_len);
1384 if (!connector) {
1385 wpa_printf(MSG_DEBUG,
1386 "DPP: Peer did not include its Connector");
1387 return;
1388 }
1389
Roshan Pius3a1667e2018-07-03 15:17:14 -07001390 res = dpp_peer_intro(&intro, hapd->conf->dpp_connector,
1391 wpabuf_head(hapd->conf->dpp_netaccesskey),
1392 wpabuf_len(hapd->conf->dpp_netaccesskey),
1393 wpabuf_head(hapd->conf->dpp_csign),
1394 wpabuf_len(hapd->conf->dpp_csign),
1395 connector, connector_len, &expire);
1396 if (res == 255) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001397 wpa_printf(MSG_INFO,
Roshan Pius3a1667e2018-07-03 15:17:14 -07001398 "DPP: Network Introduction protocol resulted in internal failure (peer "
1399 MACSTR ")", MAC2STR(src));
1400 return;
1401 }
1402 if (res != DPP_STATUS_OK) {
1403 wpa_printf(MSG_INFO,
1404 "DPP: Network Introduction protocol resulted in failure (peer "
1405 MACSTR " status %d)", MAC2STR(src), res);
1406 hostapd_dpp_send_peer_disc_resp(hapd, src, freq, trans_id[0],
1407 res);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001408 return;
1409 }
1410
Roshan Pius3a1667e2018-07-03 15:17:14 -07001411 if (!expire || (os_time_t) hapd->conf->dpp_netaccesskey_expiry < expire)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001412 expire = hapd->conf->dpp_netaccesskey_expiry;
1413 if (expire)
1414 expiration = expire - now.sec;
1415 else
1416 expiration = 0;
1417
1418 if (wpa_auth_pmksa_add2(hapd->wpa_auth, src, intro.pmk, intro.pmk_len,
1419 intro.pmkid, expiration,
1420 WPA_KEY_MGMT_DPP) < 0) {
1421 wpa_printf(MSG_ERROR, "DPP: Failed to add PMKSA cache entry");
1422 return;
1423 }
1424
Roshan Pius3a1667e2018-07-03 15:17:14 -07001425 hostapd_dpp_send_peer_disc_resp(hapd, src, freq, trans_id[0],
1426 DPP_STATUS_OK);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001427}
1428
1429
1430static void
1431hostapd_dpp_rx_pkex_exchange_req(struct hostapd_data *hapd, const u8 *src,
1432 const u8 *buf, size_t len,
1433 unsigned int freq)
1434{
1435 struct wpabuf *msg;
1436
1437 wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request from " MACSTR,
1438 MAC2STR(src));
1439
1440 /* TODO: Support multiple PKEX codes by iterating over all the enabled
1441 * values here */
1442
1443 if (!hapd->dpp_pkex_code || !hapd->dpp_pkex_bi) {
1444 wpa_printf(MSG_DEBUG,
1445 "DPP: No PKEX code configured - ignore request");
1446 return;
1447 }
1448
1449 if (hapd->dpp_pkex) {
1450 /* TODO: Support parallel operations */
1451 wpa_printf(MSG_DEBUG,
1452 "DPP: Already in PKEX session - ignore new request");
1453 return;
1454 }
1455
Roshan Pius3a1667e2018-07-03 15:17:14 -07001456 hapd->dpp_pkex = dpp_pkex_rx_exchange_req(hapd->msg_ctx,
1457 hapd->dpp_pkex_bi,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001458 hapd->own_addr, src,
1459 hapd->dpp_pkex_identifier,
1460 hapd->dpp_pkex_code,
1461 buf, len);
1462 if (!hapd->dpp_pkex) {
1463 wpa_printf(MSG_DEBUG,
1464 "DPP: Failed to process the request - ignore it");
1465 return;
1466 }
1467
1468 msg = hapd->dpp_pkex->exchange_resp;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001469 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
1470 " freq=%u type=%d", MAC2STR(src), freq,
1471 DPP_PA_PKEX_EXCHANGE_RESP);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001472 hostapd_drv_send_action(hapd, freq, 0, src,
1473 wpabuf_head(msg), wpabuf_len(msg));
Roshan Pius3a1667e2018-07-03 15:17:14 -07001474 if (hapd->dpp_pkex->failed) {
1475 wpa_printf(MSG_DEBUG,
1476 "DPP: Terminate PKEX exchange due to an earlier error");
1477 if (hapd->dpp_pkex->t > hapd->dpp_pkex->own_bi->pkex_t)
1478 hapd->dpp_pkex->own_bi->pkex_t = hapd->dpp_pkex->t;
1479 dpp_pkex_free(hapd->dpp_pkex);
1480 hapd->dpp_pkex = NULL;
1481 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001482}
1483
1484
1485static void
1486hostapd_dpp_rx_pkex_exchange_resp(struct hostapd_data *hapd, const u8 *src,
1487 const u8 *buf, size_t len, unsigned int freq)
1488{
1489 struct wpabuf *msg;
1490
1491 wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response from " MACSTR,
1492 MAC2STR(src));
1493
1494 /* TODO: Support multiple PKEX codes by iterating over all the enabled
1495 * values here */
1496
1497 if (!hapd->dpp_pkex || !hapd->dpp_pkex->initiator ||
1498 hapd->dpp_pkex->exchange_done) {
1499 wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session");
1500 return;
1501 }
1502
Roshan Pius3a1667e2018-07-03 15:17:14 -07001503 msg = dpp_pkex_rx_exchange_resp(hapd->dpp_pkex, src, buf, len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001504 if (!msg) {
1505 wpa_printf(MSG_DEBUG, "DPP: Failed to process the response");
1506 return;
1507 }
1508
1509 wpa_printf(MSG_DEBUG, "DPP: Send PKEX Commit-Reveal Request to " MACSTR,
1510 MAC2STR(src));
1511
Roshan Pius3a1667e2018-07-03 15:17:14 -07001512 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
1513 " freq=%u type=%d", MAC2STR(src), freq,
1514 DPP_PA_PKEX_COMMIT_REVEAL_REQ);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001515 hostapd_drv_send_action(hapd, freq, 0, src,
1516 wpabuf_head(msg), wpabuf_len(msg));
1517 wpabuf_free(msg);
1518}
1519
1520
1521static void
1522hostapd_dpp_rx_pkex_commit_reveal_req(struct hostapd_data *hapd, const u8 *src,
1523 const u8 *hdr, const u8 *buf, size_t len,
1524 unsigned int freq)
1525{
1526 struct wpabuf *msg;
1527 struct dpp_pkex *pkex = hapd->dpp_pkex;
1528 struct dpp_bootstrap_info *bi;
1529
1530 wpa_printf(MSG_DEBUG, "DPP: PKEX Commit-Reveal Request from " MACSTR,
1531 MAC2STR(src));
1532
1533 if (!pkex || pkex->initiator || !pkex->exchange_done) {
1534 wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session");
1535 return;
1536 }
1537
1538 msg = dpp_pkex_rx_commit_reveal_req(pkex, hdr, buf, len);
1539 if (!msg) {
1540 wpa_printf(MSG_DEBUG, "DPP: Failed to process the request");
Roshan Pius3a1667e2018-07-03 15:17:14 -07001541 if (hapd->dpp_pkex->failed) {
1542 wpa_printf(MSG_DEBUG, "DPP: Terminate PKEX exchange");
1543 if (hapd->dpp_pkex->t > hapd->dpp_pkex->own_bi->pkex_t)
1544 hapd->dpp_pkex->own_bi->pkex_t =
1545 hapd->dpp_pkex->t;
1546 dpp_pkex_free(hapd->dpp_pkex);
1547 hapd->dpp_pkex = NULL;
1548 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001549 return;
1550 }
1551
1552 wpa_printf(MSG_DEBUG, "DPP: Send PKEX Commit-Reveal Response to "
1553 MACSTR, MAC2STR(src));
1554
Roshan Pius3a1667e2018-07-03 15:17:14 -07001555 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
1556 " freq=%u type=%d", MAC2STR(src), freq,
1557 DPP_PA_PKEX_COMMIT_REVEAL_RESP);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001558 hostapd_drv_send_action(hapd, freq, 0, src,
1559 wpabuf_head(msg), wpabuf_len(msg));
1560 wpabuf_free(msg);
1561
1562 bi = os_zalloc(sizeof(*bi));
1563 if (!bi)
1564 return;
1565 bi->id = hapd_dpp_next_id(hapd);
1566 bi->type = DPP_BOOTSTRAP_PKEX;
1567 os_memcpy(bi->mac_addr, src, ETH_ALEN);
1568 bi->num_freq = 1;
1569 bi->freq[0] = freq;
1570 bi->curve = pkex->own_bi->curve;
1571 bi->pubkey = pkex->peer_bootstrap_key;
1572 pkex->peer_bootstrap_key = NULL;
1573 dpp_pkex_free(pkex);
1574 hapd->dpp_pkex = NULL;
1575 if (dpp_bootstrap_key_hash(bi) < 0) {
1576 dpp_bootstrap_info_free(bi);
1577 return;
1578 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001579 dl_list_add(&hapd->iface->interfaces->dpp_bootstrap, &bi->list);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001580}
1581
1582
1583static void
1584hostapd_dpp_rx_pkex_commit_reveal_resp(struct hostapd_data *hapd, const u8 *src,
1585 const u8 *hdr, const u8 *buf, size_t len,
1586 unsigned int freq)
1587{
1588 int res;
1589 struct dpp_bootstrap_info *bi, *own_bi;
1590 struct dpp_pkex *pkex = hapd->dpp_pkex;
1591 char cmd[500];
1592
1593 wpa_printf(MSG_DEBUG, "DPP: PKEX Commit-Reveal Response from " MACSTR,
1594 MAC2STR(src));
1595
1596 if (!pkex || !pkex->initiator || !pkex->exchange_done) {
1597 wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session");
1598 return;
1599 }
1600
1601 res = dpp_pkex_rx_commit_reveal_resp(pkex, hdr, buf, len);
1602 if (res < 0) {
1603 wpa_printf(MSG_DEBUG, "DPP: Failed to process the response");
1604 return;
1605 }
1606
1607 own_bi = pkex->own_bi;
1608
1609 bi = os_zalloc(sizeof(*bi));
1610 if (!bi)
1611 return;
1612 bi->id = hapd_dpp_next_id(hapd);
1613 bi->type = DPP_BOOTSTRAP_PKEX;
1614 os_memcpy(bi->mac_addr, src, ETH_ALEN);
1615 bi->num_freq = 1;
1616 bi->freq[0] = freq;
1617 bi->curve = own_bi->curve;
1618 bi->pubkey = pkex->peer_bootstrap_key;
1619 pkex->peer_bootstrap_key = NULL;
1620 dpp_pkex_free(pkex);
1621 hapd->dpp_pkex = NULL;
1622 if (dpp_bootstrap_key_hash(bi) < 0) {
1623 dpp_bootstrap_info_free(bi);
1624 return;
1625 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001626 dl_list_add(&hapd->iface->interfaces->dpp_bootstrap, &bi->list);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001627
1628 os_snprintf(cmd, sizeof(cmd), " peer=%u %s",
1629 bi->id,
1630 hapd->dpp_pkex_auth_cmd ? hapd->dpp_pkex_auth_cmd : "");
1631 wpa_printf(MSG_DEBUG,
1632 "DPP: Start authentication after PKEX with parameters: %s",
1633 cmd);
1634 if (hostapd_dpp_auth_init(hapd, cmd) < 0) {
1635 wpa_printf(MSG_DEBUG,
1636 "DPP: Authentication initialization failed");
1637 return;
1638 }
1639}
1640
1641
1642void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src,
1643 const u8 *buf, size_t len, unsigned int freq)
1644{
1645 u8 crypto_suite;
1646 enum dpp_public_action_frame_type type;
1647 const u8 *hdr;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001648 unsigned int pkex_t;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001649
1650 if (len < DPP_HDR_LEN)
1651 return;
1652 if (WPA_GET_BE24(buf) != OUI_WFA || buf[3] != DPP_OUI_TYPE)
1653 return;
1654 hdr = buf;
1655 buf += 4;
1656 len -= 4;
1657 crypto_suite = *buf++;
1658 type = *buf++;
1659 len -= 2;
1660
1661 wpa_printf(MSG_DEBUG,
1662 "DPP: Received DPP Public Action frame crypto suite %u type %d from "
1663 MACSTR " freq=%u",
1664 crypto_suite, type, MAC2STR(src), freq);
1665 if (crypto_suite != 1) {
1666 wpa_printf(MSG_DEBUG, "DPP: Unsupported crypto suite %u",
1667 crypto_suite);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001668 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_RX "src=" MACSTR
1669 " freq=%u type=%d ignore=unsupported-crypto-suite",
1670 MAC2STR(src), freq, type);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001671 return;
1672 }
1673 wpa_hexdump(MSG_MSGDUMP, "DPP: Received message attributes", buf, len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001674 if (dpp_check_attrs(buf, len) < 0) {
1675 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_RX "src=" MACSTR
1676 " freq=%u type=%d ignore=invalid-attributes",
1677 MAC2STR(src), freq, type);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001678 return;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001679 }
1680 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_RX "src=" MACSTR
1681 " freq=%u type=%d", MAC2STR(src), freq, type);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001682
1683 switch (type) {
1684 case DPP_PA_AUTHENTICATION_REQ:
1685 hostapd_dpp_rx_auth_req(hapd, src, hdr, buf, len, freq);
1686 break;
1687 case DPP_PA_AUTHENTICATION_RESP:
Roshan Pius3a1667e2018-07-03 15:17:14 -07001688 hostapd_dpp_rx_auth_resp(hapd, src, hdr, buf, len, freq);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001689 break;
1690 case DPP_PA_AUTHENTICATION_CONF:
1691 hostapd_dpp_rx_auth_conf(hapd, src, hdr, buf, len);
1692 break;
1693 case DPP_PA_PEER_DISCOVERY_REQ:
1694 hostapd_dpp_rx_peer_disc_req(hapd, src, buf, len, freq);
1695 break;
1696 case DPP_PA_PKEX_EXCHANGE_REQ:
1697 hostapd_dpp_rx_pkex_exchange_req(hapd, src, buf, len, freq);
1698 break;
1699 case DPP_PA_PKEX_EXCHANGE_RESP:
1700 hostapd_dpp_rx_pkex_exchange_resp(hapd, src, buf, len, freq);
1701 break;
1702 case DPP_PA_PKEX_COMMIT_REVEAL_REQ:
1703 hostapd_dpp_rx_pkex_commit_reveal_req(hapd, src, hdr, buf, len,
1704 freq);
1705 break;
1706 case DPP_PA_PKEX_COMMIT_REVEAL_RESP:
1707 hostapd_dpp_rx_pkex_commit_reveal_resp(hapd, src, hdr, buf, len,
1708 freq);
1709 break;
1710 default:
1711 wpa_printf(MSG_DEBUG,
1712 "DPP: Ignored unsupported frame subtype %d", type);
1713 break;
1714 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001715
1716 if (hapd->dpp_pkex)
1717 pkex_t = hapd->dpp_pkex->t;
1718 else if (hapd->dpp_pkex_bi)
1719 pkex_t = hapd->dpp_pkex_bi->pkex_t;
1720 else
1721 pkex_t = 0;
1722 if (pkex_t >= PKEX_COUNTER_T_LIMIT) {
1723 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_PKEX_T_LIMIT "id=0");
1724 hostapd_dpp_pkex_remove(hapd, "*");
1725 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001726}
1727
1728
1729struct wpabuf *
1730hostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa,
1731 const u8 *query, size_t query_len)
1732{
1733 struct dpp_authentication *auth = hapd->dpp_auth;
1734 struct wpabuf *resp;
1735
1736 wpa_printf(MSG_DEBUG, "DPP: GAS request from " MACSTR, MAC2STR(sa));
1737 if (!auth || !auth->auth_success ||
1738 os_memcmp(sa, auth->peer_mac_addr, ETH_ALEN) != 0) {
1739 wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
1740 return NULL;
1741 }
1742 wpa_hexdump(MSG_DEBUG,
1743 "DPP: Received Configuration Request (GAS Query Request)",
1744 query, query_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001745 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_REQ_RX "src=" MACSTR,
1746 MAC2STR(sa));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001747 resp = dpp_conf_req_rx(auth, query, query_len);
1748 if (!resp)
1749 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
1750 return resp;
1751}
1752
1753
Roshan Pius3a1667e2018-07-03 15:17:14 -07001754void hostapd_dpp_gas_status_handler(struct hostapd_data *hapd, int ok)
1755{
1756 if (!hapd->dpp_auth)
1757 return;
1758
1759 eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
1760 eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
1761 hostapd_drv_send_action_cancel_wait(hapd);
1762
1763 if (ok)
1764 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT);
1765 else
1766 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
1767 dpp_auth_deinit(hapd->dpp_auth);
1768 hapd->dpp_auth = NULL;
1769}
1770
1771
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001772static unsigned int hostapd_dpp_next_configurator_id(struct hostapd_data *hapd)
1773{
1774 struct dpp_configurator *conf;
1775 unsigned int max_id = 0;
1776
Roshan Pius3a1667e2018-07-03 15:17:14 -07001777 dl_list_for_each(conf, &hapd->iface->interfaces->dpp_configurator,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001778 struct dpp_configurator, list) {
1779 if (conf->id > max_id)
1780 max_id = conf->id;
1781 }
1782 return max_id + 1;
1783}
1784
1785
1786int hostapd_dpp_configurator_add(struct hostapd_data *hapd, const char *cmd)
1787{
1788 char *curve = NULL;
1789 char *key = NULL;
1790 u8 *privkey = NULL;
1791 size_t privkey_len = 0;
1792 int ret = -1;
1793 struct dpp_configurator *conf = NULL;
1794
1795 curve = get_param(cmd, " curve=");
1796 key = get_param(cmd, " key=");
1797
1798 if (key) {
1799 privkey_len = os_strlen(key) / 2;
1800 privkey = os_malloc(privkey_len);
1801 if (!privkey ||
1802 hexstr2bin(key, privkey, privkey_len) < 0)
1803 goto fail;
1804 }
1805
1806 conf = dpp_keygen_configurator(curve, privkey, privkey_len);
1807 if (!conf)
1808 goto fail;
1809
1810 conf->id = hostapd_dpp_next_configurator_id(hapd);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001811 dl_list_add(&hapd->iface->interfaces->dpp_configurator, &conf->list);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001812 ret = conf->id;
1813 conf = NULL;
1814fail:
1815 os_free(curve);
1816 str_clear_free(key);
1817 bin_clear_free(privkey, privkey_len);
1818 dpp_configurator_free(conf);
1819 return ret;
1820}
1821
1822
Roshan Pius3a1667e2018-07-03 15:17:14 -07001823static int dpp_configurator_del(struct hapd_interfaces *ifaces, unsigned int id)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001824{
1825 struct dpp_configurator *conf, *tmp;
1826 int found = 0;
1827
Roshan Pius3a1667e2018-07-03 15:17:14 -07001828 dl_list_for_each_safe(conf, tmp, &ifaces->dpp_configurator,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001829 struct dpp_configurator, list) {
1830 if (id && conf->id != id)
1831 continue;
1832 found = 1;
1833 dl_list_del(&conf->list);
1834 dpp_configurator_free(conf);
1835 }
1836
1837 if (id == 0)
1838 return 0; /* flush succeeds regardless of entries found */
1839 return found ? 0 : -1;
1840}
1841
1842
1843int hostapd_dpp_configurator_remove(struct hostapd_data *hapd, const char *id)
1844{
1845 unsigned int id_val;
1846
1847 if (os_strcmp(id, "*") == 0) {
1848 id_val = 0;
1849 } else {
1850 id_val = atoi(id);
1851 if (id_val == 0)
1852 return -1;
1853 }
1854
Roshan Pius3a1667e2018-07-03 15:17:14 -07001855 return dpp_configurator_del(hapd->iface->interfaces, id_val);
1856}
1857
1858
1859int hostapd_dpp_configurator_sign(struct hostapd_data *hapd, const char *cmd)
1860{
1861 struct dpp_authentication *auth;
1862 int ret = -1;
1863 char *curve = NULL;
1864
1865 auth = os_zalloc(sizeof(*auth));
1866 if (!auth)
1867 return -1;
1868
1869 curve = get_param(cmd, " curve=");
1870 hostapd_dpp_set_configurator(hapd, auth, cmd);
1871
1872 if (dpp_configurator_own_config(auth, curve, 1) == 0) {
1873 hostapd_dpp_handle_config_obj(hapd, auth);
1874 ret = 0;
1875 }
1876
1877 dpp_auth_deinit(auth);
1878 os_free(curve);
1879
1880 return ret;
1881}
1882
1883
1884int hostapd_dpp_configurator_get_key(struct hostapd_data *hapd, unsigned int id,
1885 char *buf, size_t buflen)
1886{
1887 struct dpp_configurator *conf;
1888
1889 conf = hostapd_dpp_configurator_get_id(hapd, id);
1890 if (!conf)
1891 return -1;
1892
1893 return dpp_configurator_get_key(conf, buf, buflen);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001894}
1895
1896
1897int hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd)
1898{
1899 struct dpp_bootstrap_info *own_bi;
1900 const char *pos, *end;
1901
1902 pos = os_strstr(cmd, " own=");
1903 if (!pos)
1904 return -1;
1905 pos += 5;
1906 own_bi = dpp_bootstrap_get_id(hapd, atoi(pos));
1907 if (!own_bi) {
1908 wpa_printf(MSG_DEBUG,
1909 "DPP: Identified bootstrap info not found");
1910 return -1;
1911 }
1912 if (own_bi->type != DPP_BOOTSTRAP_PKEX) {
1913 wpa_printf(MSG_DEBUG,
1914 "DPP: Identified bootstrap info not for PKEX");
1915 return -1;
1916 }
1917 hapd->dpp_pkex_bi = own_bi;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001918 own_bi->pkex_t = 0; /* clear pending errors on new code */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001919
1920 os_free(hapd->dpp_pkex_identifier);
1921 hapd->dpp_pkex_identifier = NULL;
1922 pos = os_strstr(cmd, " identifier=");
1923 if (pos) {
1924 pos += 12;
1925 end = os_strchr(pos, ' ');
1926 if (!end)
1927 return -1;
1928 hapd->dpp_pkex_identifier = os_malloc(end - pos + 1);
1929 if (!hapd->dpp_pkex_identifier)
1930 return -1;
1931 os_memcpy(hapd->dpp_pkex_identifier, pos, end - pos);
1932 hapd->dpp_pkex_identifier[end - pos] = '\0';
1933 }
1934
1935 pos = os_strstr(cmd, " code=");
1936 if (!pos)
1937 return -1;
1938 os_free(hapd->dpp_pkex_code);
1939 hapd->dpp_pkex_code = os_strdup(pos + 6);
1940 if (!hapd->dpp_pkex_code)
1941 return -1;
1942
1943 if (os_strstr(cmd, " init=1")) {
1944 struct wpabuf *msg;
1945
1946 wpa_printf(MSG_DEBUG, "DPP: Initiating PKEX");
1947 dpp_pkex_free(hapd->dpp_pkex);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001948 hapd->dpp_pkex = dpp_pkex_init(hapd->msg_ctx, own_bi,
1949 hapd->own_addr,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001950 hapd->dpp_pkex_identifier,
1951 hapd->dpp_pkex_code);
1952 if (!hapd->dpp_pkex)
1953 return -1;
1954
1955 msg = hapd->dpp_pkex->exchange_req;
1956 /* TODO: Which channel to use? */
Roshan Pius3a1667e2018-07-03 15:17:14 -07001957 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
1958 " freq=%u type=%d", MAC2STR(broadcast), 2437,
1959 DPP_PA_PKEX_EXCHANGE_REQ);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001960 hostapd_drv_send_action(hapd, 2437, 0, broadcast,
1961 wpabuf_head(msg), wpabuf_len(msg));
1962 }
1963
1964 /* TODO: Support multiple PKEX info entries */
1965
1966 os_free(hapd->dpp_pkex_auth_cmd);
1967 hapd->dpp_pkex_auth_cmd = os_strdup(cmd);
1968
1969 return 1;
1970}
1971
1972
1973int hostapd_dpp_pkex_remove(struct hostapd_data *hapd, const char *id)
1974{
1975 unsigned int id_val;
1976
1977 if (os_strcmp(id, "*") == 0) {
1978 id_val = 0;
1979 } else {
1980 id_val = atoi(id);
1981 if (id_val == 0)
1982 return -1;
1983 }
1984
1985 if ((id_val != 0 && id_val != 1) || !hapd->dpp_pkex_code)
1986 return -1;
1987
1988 /* TODO: Support multiple PKEX entries */
1989 os_free(hapd->dpp_pkex_code);
1990 hapd->dpp_pkex_code = NULL;
1991 os_free(hapd->dpp_pkex_identifier);
1992 hapd->dpp_pkex_identifier = NULL;
1993 os_free(hapd->dpp_pkex_auth_cmd);
1994 hapd->dpp_pkex_auth_cmd = NULL;
1995 hapd->dpp_pkex_bi = NULL;
1996 /* TODO: Remove dpp_pkex only if it is for the identified PKEX code */
1997 dpp_pkex_free(hapd->dpp_pkex);
1998 hapd->dpp_pkex = NULL;
1999 return 0;
2000}
2001
2002
Roshan Pius3a1667e2018-07-03 15:17:14 -07002003void hostapd_dpp_stop(struct hostapd_data *hapd)
2004{
2005 dpp_auth_deinit(hapd->dpp_auth);
2006 hapd->dpp_auth = NULL;
2007 dpp_pkex_free(hapd->dpp_pkex);
2008 hapd->dpp_pkex = NULL;
2009}
2010
2011
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002012int hostapd_dpp_init(struct hostapd_data *hapd)
2013{
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002014 hapd->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE;
2015 hapd->dpp_init_done = 1;
2016 return 0;
2017}
2018
2019
2020void hostapd_dpp_deinit(struct hostapd_data *hapd)
2021{
2022#ifdef CONFIG_TESTING_OPTIONS
2023 os_free(hapd->dpp_config_obj_override);
2024 hapd->dpp_config_obj_override = NULL;
2025 os_free(hapd->dpp_discovery_override);
2026 hapd->dpp_discovery_override = NULL;
2027 os_free(hapd->dpp_groups_override);
2028 hapd->dpp_groups_override = NULL;
2029 hapd->dpp_ignore_netaccesskey_mismatch = 0;
2030#endif /* CONFIG_TESTING_OPTIONS */
2031 if (!hapd->dpp_init_done)
2032 return;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002033 eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
2034 eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
2035 eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002036 dpp_auth_deinit(hapd->dpp_auth);
2037 hapd->dpp_auth = NULL;
2038 hostapd_dpp_pkex_remove(hapd, "*");
2039 hapd->dpp_pkex = NULL;
2040 os_free(hapd->dpp_configurator_params);
2041 hapd->dpp_configurator_params = NULL;
2042}
Roshan Pius3a1667e2018-07-03 15:17:14 -07002043
2044
2045void hostapd_dpp_init_global(struct hapd_interfaces *ifaces)
2046{
2047 dl_list_init(&ifaces->dpp_bootstrap);
2048 dl_list_init(&ifaces->dpp_configurator);
2049 ifaces->dpp_init_done = 1;
2050}
2051
2052
2053void hostapd_dpp_deinit_global(struct hapd_interfaces *ifaces)
2054{
2055 if (!ifaces->dpp_init_done)
2056 return;
2057 dpp_bootstrap_del(ifaces, 0);
2058 dpp_configurator_del(ifaces, 0);
2059}