1189251Ssam/* 2189251Ssam * Wi-Fi Protected Setup - common functionality 3214734Srpaulo * Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi> 4189251Ssam * 5189251Ssam * This program is free software; you can redistribute it and/or modify 6189251Ssam * it under the terms of the GNU General Public License version 2 as 7189251Ssam * published by the Free Software Foundation. 8189251Ssam * 9189251Ssam * Alternatively, this software may be distributed under the terms of BSD 10189251Ssam * license. 11189251Ssam * 12189251Ssam * See README and COPYING for more details. 13189251Ssam */ 14189251Ssam 15189251Ssam#include "includes.h" 16189251Ssam 17189251Ssam#include "common.h" 18214734Srpaulo#include "crypto/aes_wrap.h" 19214734Srpaulo#include "crypto/crypto.h" 20214734Srpaulo#include "crypto/dh_group5.h" 21214734Srpaulo#include "crypto/sha1.h" 22214734Srpaulo#include "crypto/sha256.h" 23189251Ssam#include "wps_i.h" 24189251Ssam#include "wps_dev_attr.h" 25189251Ssam 26189251Ssam 27189251Ssamvoid wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len, 28189251Ssam const char *label, u8 *res, size_t res_len) 29189251Ssam{ 30189251Ssam u8 i_buf[4], key_bits[4]; 31189251Ssam const u8 *addr[4]; 32189251Ssam size_t len[4]; 33189251Ssam int i, iter; 34189251Ssam u8 hash[SHA256_MAC_LEN], *opos; 35189251Ssam size_t left; 36189251Ssam 37189251Ssam WPA_PUT_BE32(key_bits, res_len * 8); 38189251Ssam 39189251Ssam addr[0] = i_buf; 40189251Ssam len[0] = sizeof(i_buf); 41189251Ssam addr[1] = label_prefix; 42189251Ssam len[1] = label_prefix_len; 43189251Ssam addr[2] = (const u8 *) label; 44189251Ssam len[2] = os_strlen(label); 45189251Ssam addr[3] = key_bits; 46189251Ssam len[3] = sizeof(key_bits); 47189251Ssam 48189251Ssam iter = (res_len + SHA256_MAC_LEN - 1) / SHA256_MAC_LEN; 49189251Ssam opos = res; 50189251Ssam left = res_len; 51189251Ssam 52189251Ssam for (i = 1; i <= iter; i++) { 53189251Ssam WPA_PUT_BE32(i_buf, i); 54189251Ssam hmac_sha256_vector(key, SHA256_MAC_LEN, 4, addr, len, hash); 55189251Ssam if (i < iter) { 56189251Ssam os_memcpy(opos, hash, SHA256_MAC_LEN); 57189251Ssam opos += SHA256_MAC_LEN; 58189251Ssam left -= SHA256_MAC_LEN; 59189251Ssam } else 60189251Ssam os_memcpy(opos, hash, left); 61189251Ssam } 62189251Ssam} 63189251Ssam 64189251Ssam 65189251Ssamint wps_derive_keys(struct wps_data *wps) 66189251Ssam{ 67189251Ssam struct wpabuf *pubkey, *dh_shared; 68189251Ssam u8 dhkey[SHA256_MAC_LEN], kdk[SHA256_MAC_LEN]; 69189251Ssam const u8 *addr[3]; 70189251Ssam size_t len[3]; 71189251Ssam u8 keys[WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN + WPS_EMSK_LEN]; 72189251Ssam 73189251Ssam if (wps->dh_privkey == NULL) { 74189251Ssam wpa_printf(MSG_DEBUG, "WPS: Own DH private key not available"); 75189251Ssam return -1; 76189251Ssam } 77189251Ssam 78189251Ssam pubkey = wps->registrar ? wps->dh_pubkey_e : wps->dh_pubkey_r; 79189251Ssam if (pubkey == NULL) { 80189251Ssam wpa_printf(MSG_DEBUG, "WPS: Peer DH public key not available"); 81189251Ssam return -1; 82189251Ssam } 83189251Ssam 84214734Srpaulo dh_shared = dh5_derive_shared(wps->dh_ctx, pubkey, wps->dh_privkey); 85214734Srpaulo dh5_free(wps->dh_ctx); 86214734Srpaulo wps->dh_ctx = NULL; 87189251Ssam dh_shared = wpabuf_zeropad(dh_shared, 192); 88189251Ssam if (dh_shared == NULL) { 89189251Ssam wpa_printf(MSG_DEBUG, "WPS: Failed to derive DH shared key"); 90189251Ssam return -1; 91189251Ssam } 92189251Ssam 93189251Ssam /* Own DH private key is not needed anymore */ 94189251Ssam wpabuf_free(wps->dh_privkey); 95189251Ssam wps->dh_privkey = NULL; 96189251Ssam 97189251Ssam wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH shared key", dh_shared); 98189251Ssam 99189251Ssam /* DHKey = SHA-256(g^AB mod p) */ 100189251Ssam addr[0] = wpabuf_head(dh_shared); 101189251Ssam len[0] = wpabuf_len(dh_shared); 102189251Ssam sha256_vector(1, addr, len, dhkey); 103189251Ssam wpa_hexdump_key(MSG_DEBUG, "WPS: DHKey", dhkey, sizeof(dhkey)); 104189251Ssam wpabuf_free(dh_shared); 105189251Ssam 106189251Ssam /* KDK = HMAC-SHA-256_DHKey(N1 || EnrolleeMAC || N2) */ 107189251Ssam addr[0] = wps->nonce_e; 108189251Ssam len[0] = WPS_NONCE_LEN; 109189251Ssam addr[1] = wps->mac_addr_e; 110189251Ssam len[1] = ETH_ALEN; 111189251Ssam addr[2] = wps->nonce_r; 112189251Ssam len[2] = WPS_NONCE_LEN; 113189251Ssam hmac_sha256_vector(dhkey, sizeof(dhkey), 3, addr, len, kdk); 114189251Ssam wpa_hexdump_key(MSG_DEBUG, "WPS: KDK", kdk, sizeof(kdk)); 115189251Ssam 116189251Ssam wps_kdf(kdk, NULL, 0, "Wi-Fi Easy and Secure Key Derivation", 117189251Ssam keys, sizeof(keys)); 118189251Ssam os_memcpy(wps->authkey, keys, WPS_AUTHKEY_LEN); 119189251Ssam os_memcpy(wps->keywrapkey, keys + WPS_AUTHKEY_LEN, WPS_KEYWRAPKEY_LEN); 120189251Ssam os_memcpy(wps->emsk, keys + WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN, 121189251Ssam WPS_EMSK_LEN); 122189251Ssam 123189251Ssam wpa_hexdump_key(MSG_DEBUG, "WPS: AuthKey", 124189251Ssam wps->authkey, WPS_AUTHKEY_LEN); 125189251Ssam wpa_hexdump_key(MSG_DEBUG, "WPS: KeyWrapKey", 126189251Ssam wps->keywrapkey, WPS_KEYWRAPKEY_LEN); 127189251Ssam wpa_hexdump_key(MSG_DEBUG, "WPS: EMSK", wps->emsk, WPS_EMSK_LEN); 128189251Ssam 129189251Ssam return 0; 130189251Ssam} 131189251Ssam 132189251Ssam 133189251Ssamvoid wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd, 134189251Ssam size_t dev_passwd_len) 135189251Ssam{ 136189251Ssam u8 hash[SHA256_MAC_LEN]; 137189251Ssam 138189251Ssam hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, dev_passwd, 139189251Ssam (dev_passwd_len + 1) / 2, hash); 140189251Ssam os_memcpy(wps->psk1, hash, WPS_PSK_LEN); 141189251Ssam hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, 142189251Ssam dev_passwd + (dev_passwd_len + 1) / 2, 143189251Ssam dev_passwd_len / 2, hash); 144189251Ssam os_memcpy(wps->psk2, hash, WPS_PSK_LEN); 145189251Ssam 146189251Ssam wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: Device Password", 147189251Ssam dev_passwd, dev_passwd_len); 148189251Ssam wpa_hexdump_key(MSG_DEBUG, "WPS: PSK1", wps->psk1, WPS_PSK_LEN); 149189251Ssam wpa_hexdump_key(MSG_DEBUG, "WPS: PSK2", wps->psk2, WPS_PSK_LEN); 150189251Ssam} 151189251Ssam 152189251Ssam 153189251Ssamstruct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr, 154189251Ssam size_t encr_len) 155189251Ssam{ 156189251Ssam struct wpabuf *decrypted; 157189251Ssam const size_t block_size = 16; 158189251Ssam size_t i; 159189251Ssam u8 pad; 160189251Ssam const u8 *pos; 161189251Ssam 162189251Ssam /* AES-128-CBC */ 163189251Ssam if (encr == NULL || encr_len < 2 * block_size || encr_len % block_size) 164189251Ssam { 165189251Ssam wpa_printf(MSG_DEBUG, "WPS: No Encrypted Settings received"); 166189251Ssam return NULL; 167189251Ssam } 168189251Ssam 169189251Ssam decrypted = wpabuf_alloc(encr_len - block_size); 170189251Ssam if (decrypted == NULL) 171189251Ssam return NULL; 172189251Ssam 173189251Ssam wpa_hexdump(MSG_MSGDUMP, "WPS: Encrypted Settings", encr, encr_len); 174189251Ssam wpabuf_put_data(decrypted, encr + block_size, encr_len - block_size); 175189251Ssam if (aes_128_cbc_decrypt(wps->keywrapkey, encr, wpabuf_mhead(decrypted), 176189251Ssam wpabuf_len(decrypted))) { 177189251Ssam wpabuf_free(decrypted); 178189251Ssam return NULL; 179189251Ssam } 180189251Ssam 181189251Ssam wpa_hexdump_buf_key(MSG_MSGDUMP, "WPS: Decrypted Encrypted Settings", 182189251Ssam decrypted); 183189251Ssam 184189251Ssam pos = wpabuf_head_u8(decrypted) + wpabuf_len(decrypted) - 1; 185189251Ssam pad = *pos; 186189251Ssam if (pad > wpabuf_len(decrypted)) { 187189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad value"); 188189251Ssam wpabuf_free(decrypted); 189189251Ssam return NULL; 190189251Ssam } 191189251Ssam for (i = 0; i < pad; i++) { 192189251Ssam if (*pos-- != pad) { 193189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad " 194189251Ssam "string"); 195189251Ssam wpabuf_free(decrypted); 196189251Ssam return NULL; 197189251Ssam } 198189251Ssam } 199189251Ssam decrypted->used -= pad; 200189251Ssam 201189251Ssam return decrypted; 202189251Ssam} 203189251Ssam 204189251Ssam 205189251Ssam/** 206189251Ssam * wps_pin_checksum - Compute PIN checksum 207189251Ssam * @pin: Seven digit PIN (i.e., eight digit PIN without the checksum digit) 208189251Ssam * Returns: Checksum digit 209189251Ssam */ 210189251Ssamunsigned int wps_pin_checksum(unsigned int pin) 211189251Ssam{ 212189251Ssam unsigned int accum = 0; 213189251Ssam while (pin) { 214189251Ssam accum += 3 * (pin % 10); 215189251Ssam pin /= 10; 216189251Ssam accum += pin % 10; 217189251Ssam pin /= 10; 218189251Ssam } 219189251Ssam 220189251Ssam return (10 - accum % 10) % 10; 221189251Ssam} 222189251Ssam 223189251Ssam 224189251Ssam/** 225189251Ssam * wps_pin_valid - Check whether a PIN has a valid checksum 226189251Ssam * @pin: Eight digit PIN (i.e., including the checksum digit) 227189251Ssam * Returns: 1 if checksum digit is valid, or 0 if not 228189251Ssam */ 229189251Ssamunsigned int wps_pin_valid(unsigned int pin) 230189251Ssam{ 231189251Ssam return wps_pin_checksum(pin / 10) == (pin % 10); 232189251Ssam} 233189251Ssam 234189251Ssam 235189251Ssam/** 236189251Ssam * wps_generate_pin - Generate a random PIN 237189251Ssam * Returns: Eight digit PIN (i.e., including the checksum digit) 238189251Ssam */ 239189251Ssamunsigned int wps_generate_pin(void) 240189251Ssam{ 241189251Ssam unsigned int val; 242189251Ssam 243189251Ssam /* Generate seven random digits for the PIN */ 244189251Ssam if (os_get_random((unsigned char *) &val, sizeof(val)) < 0) { 245189251Ssam struct os_time now; 246189251Ssam os_get_time(&now); 247189251Ssam val = os_random() ^ now.sec ^ now.usec; 248189251Ssam } 249189251Ssam val %= 10000000; 250189251Ssam 251189251Ssam /* Append checksum digit */ 252189251Ssam return val * 10 + wps_pin_checksum(val); 253189251Ssam} 254189251Ssam 255189251Ssam 256189251Ssamvoid wps_fail_event(struct wps_context *wps, enum wps_msg_type msg) 257189251Ssam{ 258189251Ssam union wps_event_data data; 259189251Ssam 260189251Ssam if (wps->event_cb == NULL) 261189251Ssam return; 262189251Ssam 263189251Ssam os_memset(&data, 0, sizeof(data)); 264189251Ssam data.fail.msg = msg; 265189251Ssam wps->event_cb(wps->cb_ctx, WPS_EV_FAIL, &data); 266189251Ssam} 267189251Ssam 268189251Ssam 269189251Ssamvoid wps_success_event(struct wps_context *wps) 270189251Ssam{ 271189251Ssam if (wps->event_cb == NULL) 272189251Ssam return; 273189251Ssam 274189251Ssam wps->event_cb(wps->cb_ctx, WPS_EV_SUCCESS, NULL); 275189251Ssam} 276189251Ssam 277189251Ssam 278189251Ssamvoid wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part) 279189251Ssam{ 280189251Ssam union wps_event_data data; 281189251Ssam 282189251Ssam if (wps->event_cb == NULL) 283189251Ssam return; 284189251Ssam 285189251Ssam os_memset(&data, 0, sizeof(data)); 286189251Ssam data.pwd_auth_fail.enrollee = enrollee; 287189251Ssam data.pwd_auth_fail.part = part; 288189251Ssam wps->event_cb(wps->cb_ctx, WPS_EV_PWD_AUTH_FAIL, &data); 289189251Ssam} 290209158Srpaulo 291209158Srpaulo 292209158Srpaulovoid wps_pbc_overlap_event(struct wps_context *wps) 293209158Srpaulo{ 294209158Srpaulo if (wps->event_cb == NULL) 295209158Srpaulo return; 296209158Srpaulo 297209158Srpaulo wps->event_cb(wps->cb_ctx, WPS_EV_PBC_OVERLAP, NULL); 298209158Srpaulo} 299209158Srpaulo 300209158Srpaulo 301209158Srpaulovoid wps_pbc_timeout_event(struct wps_context *wps) 302209158Srpaulo{ 303209158Srpaulo if (wps->event_cb == NULL) 304209158Srpaulo return; 305209158Srpaulo 306209158Srpaulo wps->event_cb(wps->cb_ctx, WPS_EV_PBC_TIMEOUT, NULL); 307209158Srpaulo} 308214734Srpaulo 309214734Srpaulo 310214734Srpaulo#ifdef CONFIG_WPS_OOB 311214734Srpaulo 312214734Srpaulostatic struct wpabuf * wps_get_oob_cred(struct wps_context *wps) 313214734Srpaulo{ 314214734Srpaulo struct wps_data data; 315214734Srpaulo struct wpabuf *plain; 316214734Srpaulo 317214734Srpaulo plain = wpabuf_alloc(500); 318214734Srpaulo if (plain == NULL) { 319214734Srpaulo wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB " 320214734Srpaulo "credential"); 321214734Srpaulo return NULL; 322214734Srpaulo } 323214734Srpaulo 324214734Srpaulo os_memset(&data, 0, sizeof(data)); 325214734Srpaulo data.wps = wps; 326214734Srpaulo data.auth_type = wps->auth_types; 327214734Srpaulo data.encr_type = wps->encr_types; 328214734Srpaulo if (wps_build_version(plain) || wps_build_cred(&data, plain)) { 329214734Srpaulo wpabuf_free(plain); 330214734Srpaulo return NULL; 331214734Srpaulo } 332214734Srpaulo 333214734Srpaulo return plain; 334214734Srpaulo} 335214734Srpaulo 336214734Srpaulo 337214734Srpaulostatic struct wpabuf * wps_get_oob_dev_pwd(struct wps_context *wps) 338214734Srpaulo{ 339214734Srpaulo struct wpabuf *data; 340214734Srpaulo 341214734Srpaulo data = wpabuf_alloc(9 + WPS_OOB_DEVICE_PASSWORD_ATTR_LEN); 342214734Srpaulo if (data == NULL) { 343214734Srpaulo wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB " 344214734Srpaulo "device password attribute"); 345214734Srpaulo return NULL; 346214734Srpaulo } 347214734Srpaulo 348214734Srpaulo wpabuf_free(wps->oob_conf.dev_password); 349214734Srpaulo wps->oob_conf.dev_password = 350214734Srpaulo wpabuf_alloc(WPS_OOB_DEVICE_PASSWORD_LEN * 2 + 1); 351214734Srpaulo if (wps->oob_conf.dev_password == NULL) { 352214734Srpaulo wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB " 353214734Srpaulo "device password"); 354214734Srpaulo wpabuf_free(data); 355214734Srpaulo return NULL; 356214734Srpaulo } 357214734Srpaulo 358214734Srpaulo if (wps_build_version(data) || 359214734Srpaulo wps_build_oob_dev_password(data, wps)) { 360214734Srpaulo wpa_printf(MSG_ERROR, "WPS: Build OOB device password " 361214734Srpaulo "attribute error"); 362214734Srpaulo wpabuf_free(data); 363214734Srpaulo return NULL; 364214734Srpaulo } 365214734Srpaulo 366214734Srpaulo return data; 367214734Srpaulo} 368214734Srpaulo 369214734Srpaulo 370214734Srpaulostatic int wps_parse_oob_dev_pwd(struct wps_context *wps, 371214734Srpaulo struct wpabuf *data) 372214734Srpaulo{ 373214734Srpaulo struct oob_conf_data *oob_conf = &wps->oob_conf; 374214734Srpaulo struct wps_parse_attr attr; 375214734Srpaulo const u8 *pos; 376214734Srpaulo 377214734Srpaulo if (wps_parse_msg(data, &attr) < 0 || 378214734Srpaulo attr.oob_dev_password == NULL) { 379214734Srpaulo wpa_printf(MSG_ERROR, "WPS: OOB device password not found"); 380214734Srpaulo return -1; 381214734Srpaulo } 382214734Srpaulo 383214734Srpaulo pos = attr.oob_dev_password; 384214734Srpaulo 385214734Srpaulo oob_conf->pubkey_hash = 386214734Srpaulo wpabuf_alloc_copy(pos, WPS_OOB_PUBKEY_HASH_LEN); 387214734Srpaulo if (oob_conf->pubkey_hash == NULL) { 388214734Srpaulo wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB " 389214734Srpaulo "public key hash"); 390214734Srpaulo return -1; 391214734Srpaulo } 392214734Srpaulo pos += WPS_OOB_PUBKEY_HASH_LEN; 393214734Srpaulo 394214734Srpaulo wps->oob_dev_pw_id = WPA_GET_BE16(pos); 395214734Srpaulo pos += sizeof(wps->oob_dev_pw_id); 396214734Srpaulo 397214734Srpaulo oob_conf->dev_password = 398214734Srpaulo wpabuf_alloc(WPS_OOB_DEVICE_PASSWORD_LEN * 2 + 1); 399214734Srpaulo if (oob_conf->dev_password == NULL) { 400214734Srpaulo wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB " 401214734Srpaulo "device password"); 402214734Srpaulo return -1; 403214734Srpaulo } 404214734Srpaulo wpa_snprintf_hex_uppercase(wpabuf_put(oob_conf->dev_password, 405214734Srpaulo wpabuf_size(oob_conf->dev_password)), 406214734Srpaulo wpabuf_size(oob_conf->dev_password), pos, 407214734Srpaulo WPS_OOB_DEVICE_PASSWORD_LEN); 408214734Srpaulo 409214734Srpaulo return 0; 410214734Srpaulo} 411214734Srpaulo 412214734Srpaulo 413214734Srpaulostatic int wps_parse_oob_cred(struct wps_context *wps, struct wpabuf *data) 414214734Srpaulo{ 415214734Srpaulo struct wpabuf msg; 416214734Srpaulo struct wps_parse_attr attr; 417214734Srpaulo size_t i; 418214734Srpaulo 419214734Srpaulo if (wps_parse_msg(data, &attr) < 0 || attr.num_cred <= 0) { 420214734Srpaulo wpa_printf(MSG_ERROR, "WPS: OOB credential not found"); 421214734Srpaulo return -1; 422214734Srpaulo } 423214734Srpaulo 424214734Srpaulo for (i = 0; i < attr.num_cred; i++) { 425214734Srpaulo struct wps_credential local_cred; 426214734Srpaulo struct wps_parse_attr cattr; 427214734Srpaulo 428214734Srpaulo os_memset(&local_cred, 0, sizeof(local_cred)); 429214734Srpaulo wpabuf_set(&msg, attr.cred[i], attr.cred_len[i]); 430214734Srpaulo if (wps_parse_msg(&msg, &cattr) < 0 || 431214734Srpaulo wps_process_cred(&cattr, &local_cred)) { 432214734Srpaulo wpa_printf(MSG_ERROR, "WPS: Failed to parse OOB " 433214734Srpaulo "credential"); 434214734Srpaulo return -1; 435214734Srpaulo } 436214734Srpaulo wps->cred_cb(wps->cb_ctx, &local_cred); 437214734Srpaulo } 438214734Srpaulo 439214734Srpaulo return 0; 440214734Srpaulo} 441214734Srpaulo 442214734Srpaulo 443214734Srpauloint wps_process_oob(struct wps_context *wps, struct oob_device_data *oob_dev, 444214734Srpaulo int registrar) 445214734Srpaulo{ 446214734Srpaulo struct wpabuf *data; 447214734Srpaulo int ret, write_f, oob_method = wps->oob_conf.oob_method; 448214734Srpaulo void *oob_priv; 449214734Srpaulo 450214734Srpaulo write_f = oob_method == OOB_METHOD_DEV_PWD_E ? !registrar : registrar; 451214734Srpaulo 452214734Srpaulo oob_priv = oob_dev->init_func(wps, oob_dev, registrar); 453214734Srpaulo if (oob_priv == NULL) { 454214734Srpaulo wpa_printf(MSG_ERROR, "WPS: Failed to initialize OOB device"); 455214734Srpaulo return -1; 456214734Srpaulo } 457214734Srpaulo 458214734Srpaulo if (write_f) { 459214734Srpaulo if (oob_method == OOB_METHOD_CRED) 460214734Srpaulo data = wps_get_oob_cred(wps); 461214734Srpaulo else 462214734Srpaulo data = wps_get_oob_dev_pwd(wps); 463214734Srpaulo 464214734Srpaulo ret = 0; 465214734Srpaulo if (data == NULL || oob_dev->write_func(oob_priv, data) < 0) 466214734Srpaulo ret = -1; 467214734Srpaulo } else { 468214734Srpaulo data = oob_dev->read_func(oob_priv); 469214734Srpaulo if (data == NULL) 470214734Srpaulo ret = -1; 471214734Srpaulo else { 472214734Srpaulo if (oob_method == OOB_METHOD_CRED) 473214734Srpaulo ret = wps_parse_oob_cred(wps, data); 474214734Srpaulo else 475214734Srpaulo ret = wps_parse_oob_dev_pwd(wps, data); 476214734Srpaulo } 477214734Srpaulo } 478214734Srpaulo wpabuf_free(data); 479214734Srpaulo oob_dev->deinit_func(oob_priv); 480214734Srpaulo 481214734Srpaulo if (ret < 0) { 482214734Srpaulo wpa_printf(MSG_ERROR, "WPS: Failed to process OOB data"); 483214734Srpaulo return -1; 484214734Srpaulo } 485214734Srpaulo 486214734Srpaulo return 0; 487214734Srpaulo} 488214734Srpaulo 489214734Srpaulo 490214734Srpaulostruct oob_device_data * wps_get_oob_device(char *device_type) 491214734Srpaulo{ 492214734Srpaulo#ifdef CONFIG_WPS_UFD 493214734Srpaulo if (os_strstr(device_type, "ufd") != NULL) 494214734Srpaulo return &oob_ufd_device_data; 495214734Srpaulo#endif /* CONFIG_WPS_UFD */ 496214734Srpaulo#ifdef CONFIG_WPS_NFC 497214734Srpaulo if (os_strstr(device_type, "nfc") != NULL) 498214734Srpaulo return &oob_nfc_device_data; 499214734Srpaulo#endif /* CONFIG_WPS_NFC */ 500214734Srpaulo 501214734Srpaulo return NULL; 502214734Srpaulo} 503214734Srpaulo 504214734Srpaulo 505214734Srpaulo#ifdef CONFIG_WPS_NFC 506214734Srpaulostruct oob_nfc_device_data * wps_get_oob_nfc_device(char *device_name) 507214734Srpaulo{ 508214734Srpaulo if (device_name == NULL) 509214734Srpaulo return NULL; 510214734Srpaulo#ifdef CONFIG_WPS_NFC_PN531 511214734Srpaulo if (os_strstr(device_name, "pn531") != NULL) 512214734Srpaulo return &oob_nfc_pn531_device_data; 513214734Srpaulo#endif /* CONFIG_WPS_NFC_PN531 */ 514214734Srpaulo 515214734Srpaulo return NULL; 516214734Srpaulo} 517214734Srpaulo#endif /* CONFIG_WPS_NFC */ 518214734Srpaulo 519214734Srpaulo 520214734Srpauloint wps_get_oob_method(char *method) 521214734Srpaulo{ 522214734Srpaulo if (os_strstr(method, "pin-e") != NULL) 523214734Srpaulo return OOB_METHOD_DEV_PWD_E; 524214734Srpaulo if (os_strstr(method, "pin-r") != NULL) 525214734Srpaulo return OOB_METHOD_DEV_PWD_R; 526214734Srpaulo if (os_strstr(method, "cred") != NULL) 527214734Srpaulo return OOB_METHOD_CRED; 528214734Srpaulo return OOB_METHOD_UNKNOWN; 529214734Srpaulo} 530214734Srpaulo 531214734Srpaulo#endif /* CONFIG_WPS_OOB */ 532214734Srpaulo 533214734Srpaulo 534214734Srpauloint wps_dev_type_str2bin(const char *str, u8 dev_type[WPS_DEV_TYPE_LEN]) 535214734Srpaulo{ 536214734Srpaulo const char *pos; 537214734Srpaulo 538214734Srpaulo /* <categ>-<OUI>-<subcateg> */ 539214734Srpaulo WPA_PUT_BE16(dev_type, atoi(str)); 540214734Srpaulo pos = os_strchr(str, '-'); 541214734Srpaulo if (pos == NULL) 542214734Srpaulo return -1; 543214734Srpaulo pos++; 544214734Srpaulo if (hexstr2bin(pos, &dev_type[2], 4)) 545214734Srpaulo return -1; 546214734Srpaulo pos = os_strchr(pos, '-'); 547214734Srpaulo if (pos == NULL) 548214734Srpaulo return -1; 549214734Srpaulo pos++; 550214734Srpaulo WPA_PUT_BE16(&dev_type[6], atoi(pos)); 551214734Srpaulo 552214734Srpaulo 553214734Srpaulo return 0; 554214734Srpaulo} 555214734Srpaulo 556214734Srpaulo 557214734Srpaulochar * wps_dev_type_bin2str(const u8 dev_type[WPS_DEV_TYPE_LEN], char *buf, 558214734Srpaulo size_t buf_len) 559214734Srpaulo{ 560214734Srpaulo int ret; 561214734Srpaulo 562214734Srpaulo ret = os_snprintf(buf, buf_len, "%u-%08X-%u", 563214734Srpaulo WPA_GET_BE16(dev_type), WPA_GET_BE32(&dev_type[2]), 564214734Srpaulo WPA_GET_BE16(&dev_type[6])); 565214734Srpaulo if (ret < 0 || (unsigned int) ret >= buf_len) 566214734Srpaulo return NULL; 567214734Srpaulo 568214734Srpaulo return buf; 569214734Srpaulo} 570214734Srpaulo 571214734Srpaulo 572214734Srpaulovoid uuid_gen_mac_addr(const u8 *mac_addr, u8 *uuid) 573214734Srpaulo{ 574214734Srpaulo const u8 *addr[2]; 575214734Srpaulo size_t len[2]; 576214734Srpaulo u8 hash[SHA1_MAC_LEN]; 577214734Srpaulo u8 nsid[16] = { 578214734Srpaulo 0x52, 0x64, 0x80, 0xf8, 579214734Srpaulo 0xc9, 0x9b, 580214734Srpaulo 0x4b, 0xe5, 581214734Srpaulo 0xa6, 0x55, 582214734Srpaulo 0x58, 0xed, 0x5f, 0x5d, 0x60, 0x84 583214734Srpaulo }; 584214734Srpaulo 585214734Srpaulo addr[0] = nsid; 586214734Srpaulo len[0] = sizeof(nsid); 587214734Srpaulo addr[1] = mac_addr; 588214734Srpaulo len[1] = 6; 589214734Srpaulo sha1_vector(2, addr, len, hash); 590214734Srpaulo os_memcpy(uuid, hash, 16); 591214734Srpaulo 592214734Srpaulo /* Version: 5 = named-based version using SHA-1 */ 593214734Srpaulo uuid[6] = (5 << 4) | (uuid[6] & 0x0f); 594214734Srpaulo 595214734Srpaulo /* Variant specified in RFC 4122 */ 596214734Srpaulo uuid[8] = 0x80 | (uuid[8] & 0x3f); 597214734Srpaulo} 598214734Srpaulo 599214734Srpaulo 600214734Srpaulou16 wps_config_methods_str2bin(const char *str) 601214734Srpaulo{ 602214734Srpaulo u16 methods = 0; 603214734Srpaulo 604214734Srpaulo if (str == NULL) { 605214734Srpaulo /* Default to enabling methods based on build configuration */ 606214734Srpaulo methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD; 607214734Srpaulo#ifdef CONFIG_WPS_UFD 608214734Srpaulo methods |= WPS_CONFIG_USBA; 609214734Srpaulo#endif /* CONFIG_WPS_UFD */ 610214734Srpaulo#ifdef CONFIG_WPS_NFC 611214734Srpaulo methods |= WPS_CONFIG_NFC_INTERFACE; 612214734Srpaulo#endif /* CONFIG_WPS_NFC */ 613214734Srpaulo } else { 614214734Srpaulo if (os_strstr(str, "usba")) 615214734Srpaulo methods |= WPS_CONFIG_USBA; 616214734Srpaulo if (os_strstr(str, "ethernet")) 617214734Srpaulo methods |= WPS_CONFIG_ETHERNET; 618214734Srpaulo if (os_strstr(str, "label")) 619214734Srpaulo methods |= WPS_CONFIG_LABEL; 620214734Srpaulo if (os_strstr(str, "display")) 621214734Srpaulo methods |= WPS_CONFIG_DISPLAY; 622214734Srpaulo if (os_strstr(str, "ext_nfc_token")) 623214734Srpaulo methods |= WPS_CONFIG_EXT_NFC_TOKEN; 624214734Srpaulo if (os_strstr(str, "int_nfc_token")) 625214734Srpaulo methods |= WPS_CONFIG_INT_NFC_TOKEN; 626214734Srpaulo if (os_strstr(str, "nfc_interface")) 627214734Srpaulo methods |= WPS_CONFIG_NFC_INTERFACE; 628214734Srpaulo if (os_strstr(str, "push_button")) 629214734Srpaulo methods |= WPS_CONFIG_PUSHBUTTON; 630214734Srpaulo if (os_strstr(str, "keypad")) 631214734Srpaulo methods |= WPS_CONFIG_KEYPAD; 632214734Srpaulo } 633214734Srpaulo 634214734Srpaulo return methods; 635214734Srpaulo} 636