xref: /netbsd/external/bsd/wpa/dist/src/wps/wps_common.c (revision 6550d01e)
1 /*
2  * Wi-Fi Protected Setup - common functionality
3  * Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * Alternatively, this software may be distributed under the terms of BSD
10  * license.
11  *
12  * See README and COPYING for more details.
13  */
14 
15 #include "includes.h"
16 
17 #include "common.h"
18 #include "crypto/aes_wrap.h"
19 #include "crypto/crypto.h"
20 #include "crypto/dh_group5.h"
21 #include "crypto/sha1.h"
22 #include "crypto/sha256.h"
23 #include "wps_i.h"
24 #include "wps_dev_attr.h"
25 
26 
27 void wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len,
28 	     const char *label, u8 *res, size_t res_len)
29 {
30 	u8 i_buf[4], key_bits[4];
31 	const u8 *addr[4];
32 	size_t len[4];
33 	int i, iter;
34 	u8 hash[SHA256_MAC_LEN], *opos;
35 	size_t left;
36 
37 	WPA_PUT_BE32(key_bits, res_len * 8);
38 
39 	addr[0] = i_buf;
40 	len[0] = sizeof(i_buf);
41 	addr[1] = label_prefix;
42 	len[1] = label_prefix_len;
43 	addr[2] = (const u8 *) label;
44 	len[2] = os_strlen(label);
45 	addr[3] = key_bits;
46 	len[3] = sizeof(key_bits);
47 
48 	iter = (res_len + SHA256_MAC_LEN - 1) / SHA256_MAC_LEN;
49 	opos = res;
50 	left = res_len;
51 
52 	for (i = 1; i <= iter; i++) {
53 		WPA_PUT_BE32(i_buf, i);
54 		hmac_sha256_vector(key, SHA256_MAC_LEN, 4, addr, len, hash);
55 		if (i < iter) {
56 			os_memcpy(opos, hash, SHA256_MAC_LEN);
57 			opos += SHA256_MAC_LEN;
58 			left -= SHA256_MAC_LEN;
59 		} else
60 			os_memcpy(opos, hash, left);
61 	}
62 }
63 
64 
65 int wps_derive_keys(struct wps_data *wps)
66 {
67 	struct wpabuf *pubkey, *dh_shared;
68 	u8 dhkey[SHA256_MAC_LEN], kdk[SHA256_MAC_LEN];
69 	const u8 *addr[3];
70 	size_t len[3];
71 	u8 keys[WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN + WPS_EMSK_LEN];
72 
73 	if (wps->dh_privkey == NULL) {
74 		wpa_printf(MSG_DEBUG, "WPS: Own DH private key not available");
75 		return -1;
76 	}
77 
78 	pubkey = wps->registrar ? wps->dh_pubkey_e : wps->dh_pubkey_r;
79 	if (pubkey == NULL) {
80 		wpa_printf(MSG_DEBUG, "WPS: Peer DH public key not available");
81 		return -1;
82 	}
83 
84 	dh_shared = dh5_derive_shared(wps->dh_ctx, pubkey, wps->dh_privkey);
85 	dh5_free(wps->dh_ctx);
86 	wps->dh_ctx = NULL;
87 	dh_shared = wpabuf_zeropad(dh_shared, 192);
88 	if (dh_shared == NULL) {
89 		wpa_printf(MSG_DEBUG, "WPS: Failed to derive DH shared key");
90 		return -1;
91 	}
92 
93 	/* Own DH private key is not needed anymore */
94 	wpabuf_free(wps->dh_privkey);
95 	wps->dh_privkey = NULL;
96 
97 	wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH shared key", dh_shared);
98 
99 	/* DHKey = SHA-256(g^AB mod p) */
100 	addr[0] = wpabuf_head(dh_shared);
101 	len[0] = wpabuf_len(dh_shared);
102 	sha256_vector(1, addr, len, dhkey);
103 	wpa_hexdump_key(MSG_DEBUG, "WPS: DHKey", dhkey, sizeof(dhkey));
104 	wpabuf_free(dh_shared);
105 
106 	/* KDK = HMAC-SHA-256_DHKey(N1 || EnrolleeMAC || N2) */
107 	addr[0] = wps->nonce_e;
108 	len[0] = WPS_NONCE_LEN;
109 	addr[1] = wps->mac_addr_e;
110 	len[1] = ETH_ALEN;
111 	addr[2] = wps->nonce_r;
112 	len[2] = WPS_NONCE_LEN;
113 	hmac_sha256_vector(dhkey, sizeof(dhkey), 3, addr, len, kdk);
114 	wpa_hexdump_key(MSG_DEBUG, "WPS: KDK", kdk, sizeof(kdk));
115 
116 	wps_kdf(kdk, NULL, 0, "Wi-Fi Easy and Secure Key Derivation",
117 		keys, sizeof(keys));
118 	os_memcpy(wps->authkey, keys, WPS_AUTHKEY_LEN);
119 	os_memcpy(wps->keywrapkey, keys + WPS_AUTHKEY_LEN, WPS_KEYWRAPKEY_LEN);
120 	os_memcpy(wps->emsk, keys + WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN,
121 		  WPS_EMSK_LEN);
122 
123 	wpa_hexdump_key(MSG_DEBUG, "WPS: AuthKey",
124 			wps->authkey, WPS_AUTHKEY_LEN);
125 	wpa_hexdump_key(MSG_DEBUG, "WPS: KeyWrapKey",
126 			wps->keywrapkey, WPS_KEYWRAPKEY_LEN);
127 	wpa_hexdump_key(MSG_DEBUG, "WPS: EMSK", wps->emsk, WPS_EMSK_LEN);
128 
129 	return 0;
130 }
131 
132 
133 void wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd,
134 		    size_t dev_passwd_len)
135 {
136 	u8 hash[SHA256_MAC_LEN];
137 
138 	hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, dev_passwd,
139 		    (dev_passwd_len + 1) / 2, hash);
140 	os_memcpy(wps->psk1, hash, WPS_PSK_LEN);
141 	hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN,
142 		    dev_passwd + (dev_passwd_len + 1) / 2,
143 		    dev_passwd_len / 2, hash);
144 	os_memcpy(wps->psk2, hash, WPS_PSK_LEN);
145 
146 	wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: Device Password",
147 			      dev_passwd, dev_passwd_len);
148 	wpa_hexdump_key(MSG_DEBUG, "WPS: PSK1", wps->psk1, WPS_PSK_LEN);
149 	wpa_hexdump_key(MSG_DEBUG, "WPS: PSK2", wps->psk2, WPS_PSK_LEN);
150 }
151 
152 
153 struct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr,
154 					  size_t encr_len)
155 {
156 	struct wpabuf *decrypted;
157 	const size_t block_size = 16;
158 	size_t i;
159 	u8 pad;
160 	const u8 *pos;
161 
162 	/* AES-128-CBC */
163 	if (encr == NULL || encr_len < 2 * block_size || encr_len % block_size)
164 	{
165 		wpa_printf(MSG_DEBUG, "WPS: No Encrypted Settings received");
166 		return NULL;
167 	}
168 
169 	decrypted = wpabuf_alloc(encr_len - block_size);
170 	if (decrypted == NULL)
171 		return NULL;
172 
173 	wpa_hexdump(MSG_MSGDUMP, "WPS: Encrypted Settings", encr, encr_len);
174 	wpabuf_put_data(decrypted, encr + block_size, encr_len - block_size);
175 	if (aes_128_cbc_decrypt(wps->keywrapkey, encr, wpabuf_mhead(decrypted),
176 				wpabuf_len(decrypted))) {
177 		wpabuf_free(decrypted);
178 		return NULL;
179 	}
180 
181 	wpa_hexdump_buf_key(MSG_MSGDUMP, "WPS: Decrypted Encrypted Settings",
182 			    decrypted);
183 
184 	pos = wpabuf_head_u8(decrypted) + wpabuf_len(decrypted) - 1;
185 	pad = *pos;
186 	if (pad > wpabuf_len(decrypted)) {
187 		wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad value");
188 		wpabuf_free(decrypted);
189 		return NULL;
190 	}
191 	for (i = 0; i < pad; i++) {
192 		if (*pos-- != pad) {
193 			wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad "
194 				   "string");
195 			wpabuf_free(decrypted);
196 			return NULL;
197 		}
198 	}
199 	decrypted->used -= pad;
200 
201 	return decrypted;
202 }
203 
204 
205 /**
206  * wps_pin_checksum - Compute PIN checksum
207  * @pin: Seven digit PIN (i.e., eight digit PIN without the checksum digit)
208  * Returns: Checksum digit
209  */
210 unsigned int wps_pin_checksum(unsigned int pin)
211 {
212 	unsigned int accum = 0;
213 	while (pin) {
214 		accum += 3 * (pin % 10);
215 		pin /= 10;
216 		accum += pin % 10;
217 		pin /= 10;
218 	}
219 
220 	return (10 - accum % 10) % 10;
221 }
222 
223 
224 /**
225  * wps_pin_valid - Check whether a PIN has a valid checksum
226  * @pin: Eight digit PIN (i.e., including the checksum digit)
227  * Returns: 1 if checksum digit is valid, or 0 if not
228  */
229 unsigned int wps_pin_valid(unsigned int pin)
230 {
231 	return wps_pin_checksum(pin / 10) == (pin % 10);
232 }
233 
234 
235 /**
236  * wps_generate_pin - Generate a random PIN
237  * Returns: Eight digit PIN (i.e., including the checksum digit)
238  */
239 unsigned int wps_generate_pin(void)
240 {
241 	unsigned int val;
242 
243 	/* Generate seven random digits for the PIN */
244 	if (os_get_random((unsigned char *) &val, sizeof(val)) < 0) {
245 		struct os_time now;
246 		os_get_time(&now);
247 		val = os_random() ^ now.sec ^ now.usec;
248 	}
249 	val %= 10000000;
250 
251 	/* Append checksum digit */
252 	return val * 10 + wps_pin_checksum(val);
253 }
254 
255 
256 void wps_fail_event(struct wps_context *wps, enum wps_msg_type msg)
257 {
258 	union wps_event_data data;
259 
260 	if (wps->event_cb == NULL)
261 		return;
262 
263 	os_memset(&data, 0, sizeof(data));
264 	data.fail.msg = msg;
265 	wps->event_cb(wps->cb_ctx, WPS_EV_FAIL, &data);
266 }
267 
268 
269 void wps_success_event(struct wps_context *wps)
270 {
271 	if (wps->event_cb == NULL)
272 		return;
273 
274 	wps->event_cb(wps->cb_ctx, WPS_EV_SUCCESS, NULL);
275 }
276 
277 
278 void wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part)
279 {
280 	union wps_event_data data;
281 
282 	if (wps->event_cb == NULL)
283 		return;
284 
285 	os_memset(&data, 0, sizeof(data));
286 	data.pwd_auth_fail.enrollee = enrollee;
287 	data.pwd_auth_fail.part = part;
288 	wps->event_cb(wps->cb_ctx, WPS_EV_PWD_AUTH_FAIL, &data);
289 }
290 
291 
292 void wps_pbc_overlap_event(struct wps_context *wps)
293 {
294 	if (wps->event_cb == NULL)
295 		return;
296 
297 	wps->event_cb(wps->cb_ctx, WPS_EV_PBC_OVERLAP, NULL);
298 }
299 
300 
301 void wps_pbc_timeout_event(struct wps_context *wps)
302 {
303 	if (wps->event_cb == NULL)
304 		return;
305 
306 	wps->event_cb(wps->cb_ctx, WPS_EV_PBC_TIMEOUT, NULL);
307 }
308 
309 
310 #ifdef CONFIG_WPS_OOB
311 
312 static struct wpabuf * wps_get_oob_cred(struct wps_context *wps)
313 {
314 	struct wps_data data;
315 	struct wpabuf *plain;
316 
317 	plain = wpabuf_alloc(500);
318 	if (plain == NULL) {
319 		wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
320 			   "credential");
321 		return NULL;
322 	}
323 
324 	os_memset(&data, 0, sizeof(data));
325 	data.wps = wps;
326 	data.auth_type = wps->auth_types;
327 	data.encr_type = wps->encr_types;
328 	if (wps_build_version(plain) || wps_build_cred(&data, plain)) {
329 		wpabuf_free(plain);
330 		return NULL;
331 	}
332 
333 	return plain;
334 }
335 
336 
337 static struct wpabuf * wps_get_oob_dev_pwd(struct wps_context *wps)
338 {
339 	struct wpabuf *data;
340 
341 	data = wpabuf_alloc(9 + WPS_OOB_DEVICE_PASSWORD_ATTR_LEN);
342 	if (data == NULL) {
343 		wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
344 			   "device password attribute");
345 		return NULL;
346 	}
347 
348 	wpabuf_free(wps->oob_conf.dev_password);
349 	wps->oob_conf.dev_password =
350 		wpabuf_alloc(WPS_OOB_DEVICE_PASSWORD_LEN * 2 + 1);
351 	if (wps->oob_conf.dev_password == NULL) {
352 		wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
353 			   "device password");
354 		wpabuf_free(data);
355 		return NULL;
356 	}
357 
358 	if (wps_build_version(data) ||
359 	    wps_build_oob_dev_password(data, wps)) {
360 		wpa_printf(MSG_ERROR, "WPS: Build OOB device password "
361 			   "attribute error");
362 		wpabuf_free(data);
363 		return NULL;
364 	}
365 
366 	return data;
367 }
368 
369 
370 static int wps_parse_oob_dev_pwd(struct wps_context *wps,
371 				 struct wpabuf *data)
372 {
373 	struct oob_conf_data *oob_conf = &wps->oob_conf;
374 	struct wps_parse_attr attr;
375 	const u8 *pos;
376 
377 	if (wps_parse_msg(data, &attr) < 0 ||
378 	    attr.oob_dev_password == NULL) {
379 		wpa_printf(MSG_ERROR, "WPS: OOB device password not found");
380 		return -1;
381 	}
382 
383 	pos = attr.oob_dev_password;
384 
385 	oob_conf->pubkey_hash =
386 		wpabuf_alloc_copy(pos, WPS_OOB_PUBKEY_HASH_LEN);
387 	if (oob_conf->pubkey_hash == NULL) {
388 		wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
389 			   "public key hash");
390 		return -1;
391 	}
392 	pos += WPS_OOB_PUBKEY_HASH_LEN;
393 
394 	wps->oob_dev_pw_id = WPA_GET_BE16(pos);
395 	pos += sizeof(wps->oob_dev_pw_id);
396 
397 	oob_conf->dev_password =
398 		wpabuf_alloc(WPS_OOB_DEVICE_PASSWORD_LEN * 2 + 1);
399 	if (oob_conf->dev_password == NULL) {
400 		wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
401 			   "device password");
402 		return -1;
403 	}
404 	wpa_snprintf_hex_uppercase(wpabuf_put(oob_conf->dev_password,
405 				   wpabuf_size(oob_conf->dev_password)),
406 				   wpabuf_size(oob_conf->dev_password), pos,
407 				   WPS_OOB_DEVICE_PASSWORD_LEN);
408 
409 	return 0;
410 }
411 
412 
413 static int wps_parse_oob_cred(struct wps_context *wps, struct wpabuf *data)
414 {
415 	struct wpabuf msg;
416 	struct wps_parse_attr attr;
417 	size_t i;
418 
419 	if (wps_parse_msg(data, &attr) < 0 || attr.num_cred <= 0) {
420 		wpa_printf(MSG_ERROR, "WPS: OOB credential not found");
421 		return -1;
422 	}
423 
424 	for (i = 0; i < attr.num_cred; i++) {
425 		struct wps_credential local_cred;
426 		struct wps_parse_attr cattr;
427 
428 		os_memset(&local_cred, 0, sizeof(local_cred));
429 		wpabuf_set(&msg, attr.cred[i], attr.cred_len[i]);
430 		if (wps_parse_msg(&msg, &cattr) < 0 ||
431 		    wps_process_cred(&cattr, &local_cred)) {
432 			wpa_printf(MSG_ERROR, "WPS: Failed to parse OOB "
433 				   "credential");
434 			return -1;
435 		}
436 		wps->cred_cb(wps->cb_ctx, &local_cred);
437 	}
438 
439 	return 0;
440 }
441 
442 
443 int wps_process_oob(struct wps_context *wps, struct oob_device_data *oob_dev,
444 		    int registrar)
445 {
446 	struct wpabuf *data;
447 	int ret, write_f, oob_method = wps->oob_conf.oob_method;
448 	void *oob_priv;
449 
450 	write_f = oob_method == OOB_METHOD_DEV_PWD_E ? !registrar : registrar;
451 
452 	oob_priv = oob_dev->init_func(wps, oob_dev, registrar);
453 	if (oob_priv == NULL) {
454 		wpa_printf(MSG_ERROR, "WPS: Failed to initialize OOB device");
455 		return -1;
456 	}
457 
458 	if (write_f) {
459 		if (oob_method == OOB_METHOD_CRED)
460 			data = wps_get_oob_cred(wps);
461 		else
462 			data = wps_get_oob_dev_pwd(wps);
463 
464 		ret = 0;
465 		if (data == NULL || oob_dev->write_func(oob_priv, data) < 0)
466 			ret = -1;
467 	} else {
468 		data = oob_dev->read_func(oob_priv);
469 		if (data == NULL)
470 			ret = -1;
471 		else {
472 			if (oob_method == OOB_METHOD_CRED)
473 				ret = wps_parse_oob_cred(wps, data);
474 			else
475 				ret = wps_parse_oob_dev_pwd(wps, data);
476 		}
477 	}
478 	wpabuf_free(data);
479 	oob_dev->deinit_func(oob_priv);
480 
481 	if (ret < 0) {
482 		wpa_printf(MSG_ERROR, "WPS: Failed to process OOB data");
483 		return -1;
484 	}
485 
486 	return 0;
487 }
488 
489 
490 struct oob_device_data * wps_get_oob_device(char *device_type)
491 {
492 #ifdef CONFIG_WPS_UFD
493 	if (os_strstr(device_type, "ufd") != NULL)
494 		return &oob_ufd_device_data;
495 #endif /* CONFIG_WPS_UFD */
496 #ifdef CONFIG_WPS_NFC
497 	if (os_strstr(device_type, "nfc") != NULL)
498 		return &oob_nfc_device_data;
499 #endif /* CONFIG_WPS_NFC */
500 
501 	return NULL;
502 }
503 
504 
505 #ifdef CONFIG_WPS_NFC
506 struct oob_nfc_device_data * wps_get_oob_nfc_device(char *device_name)
507 {
508 	if (device_name == NULL)
509 		return NULL;
510 #ifdef CONFIG_WPS_NFC_PN531
511 	if (os_strstr(device_name, "pn531") != NULL)
512 		return &oob_nfc_pn531_device_data;
513 #endif /* CONFIG_WPS_NFC_PN531 */
514 
515 	return NULL;
516 }
517 #endif /* CONFIG_WPS_NFC */
518 
519 
520 int wps_get_oob_method(char *method)
521 {
522 	if (os_strstr(method, "pin-e") != NULL)
523 		return OOB_METHOD_DEV_PWD_E;
524 	if (os_strstr(method, "pin-r") != NULL)
525 		return OOB_METHOD_DEV_PWD_R;
526 	if (os_strstr(method, "cred") != NULL)
527 		return OOB_METHOD_CRED;
528 	return OOB_METHOD_UNKNOWN;
529 }
530 
531 #endif /* CONFIG_WPS_OOB */
532 
533 
534 int wps_dev_type_str2bin(const char *str, u8 dev_type[WPS_DEV_TYPE_LEN])
535 {
536 	const char *pos;
537 
538 	/* <categ>-<OUI>-<subcateg> */
539 	WPA_PUT_BE16(dev_type, atoi(str));
540 	pos = os_strchr(str, '-');
541 	if (pos == NULL)
542 		return -1;
543 	pos++;
544 	if (hexstr2bin(pos, &dev_type[2], 4))
545 		return -1;
546 	pos = os_strchr(pos, '-');
547 	if (pos == NULL)
548 		return -1;
549 	pos++;
550 	WPA_PUT_BE16(&dev_type[6], atoi(pos));
551 
552 
553 	return 0;
554 }
555 
556 
557 char * wps_dev_type_bin2str(const u8 dev_type[WPS_DEV_TYPE_LEN], char *buf,
558 			    size_t buf_len)
559 {
560 	int ret;
561 
562 	ret = os_snprintf(buf, buf_len, "%u-%08X-%u",
563 			  WPA_GET_BE16(dev_type), WPA_GET_BE32(&dev_type[2]),
564 			  WPA_GET_BE16(&dev_type[6]));
565 	if (ret < 0 || (unsigned int) ret >= buf_len)
566 		return NULL;
567 
568 	return buf;
569 }
570 
571 
572 void uuid_gen_mac_addr(const u8 *mac_addr, u8 *uuid)
573 {
574 	const u8 *addr[2];
575 	size_t len[2];
576 	u8 hash[SHA1_MAC_LEN];
577 	u8 nsid[16] = {
578 		0x52, 0x64, 0x80, 0xf8,
579 		0xc9, 0x9b,
580 		0x4b, 0xe5,
581 		0xa6, 0x55,
582 		0x58, 0xed, 0x5f, 0x5d, 0x60, 0x84
583 	};
584 
585 	addr[0] = nsid;
586 	len[0] = sizeof(nsid);
587 	addr[1] = mac_addr;
588 	len[1] = 6;
589 	sha1_vector(2, addr, len, hash);
590 	os_memcpy(uuid, hash, 16);
591 
592 	/* Version: 5 = named-based version using SHA-1 */
593 	uuid[6] = (5 << 4) | (uuid[6] & 0x0f);
594 
595 	/* Variant specified in RFC 4122 */
596 	uuid[8] = 0x80 | (uuid[8] & 0x3f);
597 }
598 
599 
600 u16 wps_config_methods_str2bin(const char *str)
601 {
602 	u16 methods = 0;
603 
604 	if (str == NULL) {
605 		/* Default to enabling methods based on build configuration */
606 		methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
607 #ifdef CONFIG_WPS_UFD
608 		methods |= WPS_CONFIG_USBA;
609 #endif /* CONFIG_WPS_UFD */
610 #ifdef CONFIG_WPS_NFC
611 		methods |= WPS_CONFIG_NFC_INTERFACE;
612 #endif /* CONFIG_WPS_NFC */
613 	} else {
614 		if (os_strstr(str, "usba"))
615 			methods |= WPS_CONFIG_USBA;
616 		if (os_strstr(str, "ethernet"))
617 			methods |= WPS_CONFIG_ETHERNET;
618 		if (os_strstr(str, "label"))
619 			methods |= WPS_CONFIG_LABEL;
620 		if (os_strstr(str, "display"))
621 			methods |= WPS_CONFIG_DISPLAY;
622 		if (os_strstr(str, "ext_nfc_token"))
623 			methods |= WPS_CONFIG_EXT_NFC_TOKEN;
624 		if (os_strstr(str, "int_nfc_token"))
625 			methods |= WPS_CONFIG_INT_NFC_TOKEN;
626 		if (os_strstr(str, "nfc_interface"))
627 			methods |= WPS_CONFIG_NFC_INTERFACE;
628 		if (os_strstr(str, "push_button"))
629 			methods |= WPS_CONFIG_PUSHBUTTON;
630 		if (os_strstr(str, "keypad"))
631 			methods |= WPS_CONFIG_KEYPAD;
632 	}
633 
634 	return methods;
635 }
636