X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=src%2Fwps%2Fwps_common.c;h=82e6311c6eae657d8affccc92d2567ceef36d999;hb=e64e3d245ee40f9e12a26a4f07ec3888dc87e875;hp=1a4ae036382d82562d5bea94fa1067f0f916c183;hpb=fced73755fae986b14f74038eb0151ffdb4b6094;p=libeap.git diff --git a/src/wps/wps_common.c b/src/wps/wps_common.c index 1a4ae03..82e6311 100644 --- a/src/wps/wps_common.c +++ b/src/wps/wps_common.c @@ -1,6 +1,6 @@ /* * Wi-Fi Protected Setup - common functionality - * Copyright (c) 2008, Jouni Malinen + * Copyright (c) 2008-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -15,429 +15,21 @@ #include "includes.h" #include "common.h" -#include "dh_groups.h" -#include "sha256.h" -#include "aes_wrap.h" -#include "crypto.h" +#include "crypto/aes_wrap.h" +#include "crypto/crypto.h" +#include "crypto/dh_group5.h" +#include "crypto/sha1.h" +#include "crypto/sha256.h" #include "wps_i.h" +#include "wps_dev_attr.h" -static int wps_set_attr(struct wps_parse_attr *attr, u16 type, - const u8 *pos, u16 len) -{ - switch (type) { - case ATTR_VERSION: - if (len != 1) { - wpa_printf(MSG_DEBUG, "WPS: Invalid Version length %u", - len); - return -1; - } - attr->version = pos; - break; - case ATTR_MSG_TYPE: - if (len != 1) { - wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type " - "length %u", len); - return -1; - } - attr->msg_type = pos; - break; - case ATTR_ENROLLEE_NONCE: - if (len != WPS_NONCE_LEN) { - wpa_printf(MSG_DEBUG, "WPS: Invalid Enrollee Nonce " - "length %u", len); - return -1; - } - attr->enrollee_nonce = pos; - break; - case ATTR_REGISTRAR_NONCE: - if (len != WPS_NONCE_LEN) { - wpa_printf(MSG_DEBUG, "WPS: Invalid Registrar Nonce " - "length %u", len); - return -1; - } - attr->registrar_nonce = pos; - break; - case ATTR_UUID_E: - if (len != WPS_UUID_LEN) { - wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-E length %u", - len); - return -1; - } - attr->uuid_e = pos; - break; - case ATTR_UUID_R: - if (len != WPS_UUID_LEN) { - wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-R length %u", - len); - return -1; - } - attr->uuid_r = pos; - break; - case ATTR_AUTH_TYPE_FLAGS: - if (len != 2) { - wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication " - "Type Flags length %u", len); - return -1; - } - attr->auth_type_flags = pos; - break; - case ATTR_ENCR_TYPE_FLAGS: - if (len != 2) { - wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption Type " - "Flags length %u", len); - return -1; - } - attr->encr_type_flags = pos; - break; - case ATTR_CONN_TYPE_FLAGS: - if (len != 1) { - wpa_printf(MSG_DEBUG, "WPS: Invalid Connection Type " - "Flags length %u", len); - return -1; - } - attr->conn_type_flags = pos; - break; - case ATTR_CONFIG_METHODS: - if (len != 2) { - wpa_printf(MSG_DEBUG, "WPS: Invalid Config Methods " - "length %u", len); - return -1; - } - attr->config_methods = pos; - break; - case ATTR_SELECTED_REGISTRAR_CONFIG_METHODS: - if (len != 2) { - wpa_printf(MSG_DEBUG, "WPS: Invalid Selected " - "Registrar Config Methods length %u", len); - return -1; - } - attr->sel_reg_config_methods = pos; - break; - case ATTR_PRIMARY_DEV_TYPE: - if (len != sizeof(struct wps_dev_type)) { - wpa_printf(MSG_DEBUG, "WPS: Invalid Primary Device " - "Type length %u", len); - return -1; - } - attr->primary_dev_type = pos; - break; - case ATTR_RF_BANDS: - if (len != 1) { - wpa_printf(MSG_DEBUG, "WPS: Invalid RF Bands length " - "%u", len); - return -1; - } - attr->rf_bands = pos; - break; - case ATTR_ASSOC_STATE: - if (len != 2) { - wpa_printf(MSG_DEBUG, "WPS: Invalid Association State " - "length %u", len); - return -1; - } - attr->assoc_state = pos; - break; - case ATTR_CONFIG_ERROR: - if (len != 2) { - wpa_printf(MSG_DEBUG, "WPS: Invalid Configuration " - "Error length %u", len); - return -1; - } - attr->config_error = pos; - break; - case ATTR_DEV_PASSWORD_ID: - if (len != 2) { - wpa_printf(MSG_DEBUG, "WPS: Invalid Device Password " - "ID length %u", len); - return -1; - } - attr->dev_password_id = pos; - break; - case ATTR_OS_VERSION: - if (len != 4) { - wpa_printf(MSG_DEBUG, "WPS: Invalid OS Version length " - "%u", len); - return -1; - } - attr->os_version = pos; - break; - case ATTR_WPS_STATE: - if (len != 1) { - wpa_printf(MSG_DEBUG, "WPS: Invalid Wi-Fi Protected " - "Setup State length %u", len); - return -1; - } - attr->wps_state = pos; - break; - case ATTR_AUTHENTICATOR: - if (len != WPS_AUTHENTICATOR_LEN) { - wpa_printf(MSG_DEBUG, "WPS: Invalid Authenticator " - "length %u", len); - return -1; - } - attr->authenticator = pos; - break; - case ATTR_R_HASH1: - if (len != WPS_HASH_LEN) { - wpa_printf(MSG_DEBUG, "WPS: Invalid R-Hash1 length %u", - len); - return -1; - } - attr->r_hash1 = pos; - break; - case ATTR_R_HASH2: - if (len != WPS_HASH_LEN) { - wpa_printf(MSG_DEBUG, "WPS: Invalid R-Hash2 length %u", - len); - return -1; - } - attr->r_hash2 = pos; - break; - case ATTR_E_HASH1: - if (len != WPS_HASH_LEN) { - wpa_printf(MSG_DEBUG, "WPS: Invalid E-Hash1 length %u", - len); - return -1; - } - attr->e_hash1 = pos; - break; - case ATTR_E_HASH2: - if (len != WPS_HASH_LEN) { - wpa_printf(MSG_DEBUG, "WPS: Invalid E-Hash2 length %u", - len); - return -1; - } - attr->e_hash2 = pos; - break; - case ATTR_R_SNONCE1: - if (len != WPS_SECRET_NONCE_LEN) { - wpa_printf(MSG_DEBUG, "WPS: Invalid R-SNonce1 length " - "%u", len); - return -1; - } - attr->r_snonce1 = pos; - break; - case ATTR_R_SNONCE2: - if (len != WPS_SECRET_NONCE_LEN) { - wpa_printf(MSG_DEBUG, "WPS: Invalid R-SNonce2 length " - "%u", len); - return -1; - } - attr->r_snonce2 = pos; - break; - case ATTR_E_SNONCE1: - if (len != WPS_SECRET_NONCE_LEN) { - wpa_printf(MSG_DEBUG, "WPS: Invalid E-SNonce1 length " - "%u", len); - return -1; - } - attr->e_snonce1 = pos; - break; - case ATTR_E_SNONCE2: - if (len != WPS_SECRET_NONCE_LEN) { - wpa_printf(MSG_DEBUG, "WPS: Invalid E-SNonce2 length " - "%u", len); - return -1; - } - attr->e_snonce2 = pos; - break; - case ATTR_KEY_WRAP_AUTH: - if (len != WPS_KWA_LEN) { - wpa_printf(MSG_DEBUG, "WPS: Invalid Key Wrap " - "Authenticator length %u", len); - return -1; - } - attr->key_wrap_auth = pos; - break; - case ATTR_AUTH_TYPE: - if (len != 2) { - wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication " - "Type length %u", len); - return -1; - } - attr->auth_type = pos; - break; - case ATTR_ENCR_TYPE: - if (len != 2) { - wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption " - "Type length %u", len); - return -1; - } - attr->encr_type = pos; - break; - case ATTR_NETWORK_INDEX: - if (len != 1) { - wpa_printf(MSG_DEBUG, "WPS: Invalid Network Index " - "length %u", len); - return -1; - } - attr->network_idx = pos; - break; - case ATTR_NETWORK_KEY_INDEX: - if (len != 1) { - wpa_printf(MSG_DEBUG, "WPS: Invalid Network Key Index " - "length %u", len); - return -1; - } - attr->network_key_idx = pos; - break; - case ATTR_MAC_ADDR: - if (len != ETH_ALEN) { - wpa_printf(MSG_DEBUG, "WPS: Invalid MAC Address " - "length %u", len); - return -1; - } - attr->mac_addr = pos; - break; - case ATTR_KEY_PROVIDED_AUTO: - if (len != 1) { - wpa_printf(MSG_DEBUG, "WPS: Invalid Key Provided " - "Automatically length %u", len); - return -1; - } - attr->key_prov_auto = pos; - break; - case ATTR_802_1X_ENABLED: - if (len != 1) { - wpa_printf(MSG_DEBUG, "WPS: Invalid 802.1X Enabled " - "length %u", len); - return -1; - } - attr->dot1x_enabled = pos; - break; - case ATTR_SELECTED_REGISTRAR: - if (len != 1) { - wpa_printf(MSG_DEBUG, "WPS: Invalid Selected Registrar" - " length %u", len); - return -1; - } - attr->selected_registrar = pos; - break; - case ATTR_REQUEST_TYPE: - if (len != 1) { - wpa_printf(MSG_DEBUG, "WPS: Invalid Request Type " - "length %u", len); - return -1; - } - attr->request_type = pos; - break; - case ATTR_RESPONSE_TYPE: - if (len != 1) { - wpa_printf(MSG_DEBUG, "WPS: Invalid Response Type " - "length %u", len); - return -1; - } - attr->request_type = pos; - break; - case ATTR_MANUFACTURER: - attr->manufacturer = pos; - attr->manufacturer_len = len; - break; - case ATTR_MODEL_NAME: - attr->model_name = pos; - attr->model_name_len = len; - break; - case ATTR_MODEL_NUMBER: - attr->model_number = pos; - attr->model_number_len = len; - break; - case ATTR_SERIAL_NUMBER: - attr->serial_number = pos; - attr->serial_number_len = len; - break; - case ATTR_DEV_NAME: - attr->dev_name = pos; - attr->dev_name_len = len; - break; - case ATTR_PUBLIC_KEY: - attr->public_key = pos; - attr->public_key_len = len; - break; - case ATTR_ENCR_SETTINGS: - attr->encr_settings = pos; - attr->encr_settings_len = len; - break; - case ATTR_CRED: - if (attr->num_cred >= MAX_CRED_COUNT) { - wpa_printf(MSG_DEBUG, "WPS: Skipped Credential " - "attribute (max %d credentials)", - MAX_CRED_COUNT); - break; - } - attr->cred[attr->num_cred] = pos; - attr->cred_len[attr->num_cred] = len; - attr->num_cred++; - break; - case ATTR_SSID: - attr->ssid = pos; - attr->ssid_len = len; - break; - case ATTR_NETWORK_KEY: - attr->network_key = pos; - attr->network_key_len = len; - break; - case ATTR_EAP_TYPE: - attr->eap_type = pos; - attr->eap_type_len = len; - break; - case ATTR_EAP_IDENTITY: - attr->eap_identity = pos; - attr->eap_identity_len = len; - break; - default: - wpa_printf(MSG_DEBUG, "WPS: Unsupported attribute type 0x%x " - "len=%u", type, len); - break; - } - - return 0; -} - - -int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr) -{ - const u8 *pos, *end; - u16 type, len; - - os_memset(attr, 0, sizeof(*attr)); - pos = wpabuf_head(msg); - end = pos + wpabuf_len(msg); - - while (pos < end) { - if (end - pos < 4) { - wpa_printf(MSG_DEBUG, "WPS: Invalid message - " - "%lu bytes remaining", - (unsigned long) (end - pos)); - return -1; - } - - type = WPA_GET_BE16(pos); - pos += 2; - len = WPA_GET_BE16(pos); - pos += 2; - wpa_printf(MSG_MSGDUMP, "WPS: attr type=0x%x len=%u", - type, len); - if (len > end - pos) { - wpa_printf(MSG_DEBUG, "WPS: Attribute overflow"); - return -1; - } - - if (wps_set_attr(attr, type, pos, len) < 0) - return -1; - - pos += len; - } - - return 0; -} - - -void wps_kdf(const u8 *key, const char *label, u8 *res, size_t res_len) +void wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len, + const char *label, u8 *res, size_t res_len) { u8 i_buf[4], key_bits[4]; - const u8 *addr[3]; - size_t len[3]; + const u8 *addr[4]; + size_t len[4]; int i, iter; u8 hash[SHA256_MAC_LEN], *opos; size_t left; @@ -446,10 +38,12 @@ void wps_kdf(const u8 *key, const char *label, u8 *res, size_t res_len) addr[0] = i_buf; len[0] = sizeof(i_buf); - addr[1] = (const u8 *) label; - len[1] = os_strlen(label); - addr[2] = key_bits; - len[2] = sizeof(key_bits); + addr[1] = label_prefix; + len[1] = label_prefix_len; + addr[2] = (const u8 *) label; + len[2] = os_strlen(label); + addr[3] = key_bits; + len[3] = sizeof(key_bits); iter = (res_len + SHA256_MAC_LEN - 1) / SHA256_MAC_LEN; opos = res; @@ -457,7 +51,7 @@ void wps_kdf(const u8 *key, const char *label, u8 *res, size_t res_len) for (i = 1; i <= iter; i++) { WPA_PUT_BE32(i_buf, i); - hmac_sha256_vector(key, SHA256_MAC_LEN, 3, addr, len, hash); + hmac_sha256_vector(key, SHA256_MAC_LEN, 4, addr, len, hash); if (i < iter) { os_memcpy(opos, hash, SHA256_MAC_LEN); opos += SHA256_MAC_LEN; @@ -468,34 +62,6 @@ void wps_kdf(const u8 *key, const char *label, u8 *res, size_t res_len) } -int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg) -{ - struct wpabuf *pubkey; - - wpa_printf(MSG_DEBUG, "WPS: * Public Key"); - pubkey = dh_init(dh_groups_get(WPS_DH_GROUP), &wps->dh_privkey); - if (pubkey == NULL) { - wpa_printf(MSG_DEBUG, "WPS: Failed to initialize " - "Diffie-Hellman handshake"); - return -1; - } - - wpabuf_put_be16(msg, ATTR_PUBLIC_KEY); - wpabuf_put_be16(msg, wpabuf_len(pubkey)); - wpabuf_put_buf(msg, pubkey); - - if (wps->registrar) { - wpabuf_free(wps->dh_pubkey_r); - wps->dh_pubkey_r = pubkey; - } else { - wpabuf_free(wps->dh_pubkey_e); - wps->dh_pubkey_e = pubkey; - } - - return 0; -} - - int wps_derive_keys(struct wps_data *wps) { struct wpabuf *pubkey, *dh_shared; @@ -515,8 +81,12 @@ int wps_derive_keys(struct wps_data *wps) return -1; } - dh_shared = dh_derive_shared(pubkey, wps->dh_privkey, - dh_groups_get(WPS_DH_GROUP)); + wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH Private Key", wps->dh_privkey); + wpa_hexdump_buf(MSG_DEBUG, "WPS: DH peer Public Key", pubkey); + dh_shared = dh5_derive_shared(wps->dh_ctx, pubkey, wps->dh_privkey); + dh5_free(wps->dh_ctx); + wps->dh_ctx = NULL; + dh_shared = wpabuf_zeropad(dh_shared, 192); if (dh_shared == NULL) { wpa_printf(MSG_DEBUG, "WPS: Failed to derive DH shared key"); return -1; @@ -545,7 +115,7 @@ int wps_derive_keys(struct wps_data *wps) hmac_sha256_vector(dhkey, sizeof(dhkey), 3, addr, len, kdk); wpa_hexdump_key(MSG_DEBUG, "WPS: KDK", kdk, sizeof(kdk)); - wps_kdf(kdk, "Wi-Fi Easy and Secure Key Derivation", + wps_kdf(kdk, NULL, 0, "Wi-Fi Easy and Secure Key Derivation", keys, sizeof(keys)); os_memcpy(wps->authkey, keys, WPS_AUTHKEY_LEN); os_memcpy(wps->keywrapkey, keys + WPS_AUTHKEY_LEN, WPS_KEYWRAPKEY_LEN); @@ -562,73 +132,6 @@ int wps_derive_keys(struct wps_data *wps) } -int wps_build_authenticator(struct wps_data *wps, struct wpabuf *msg) -{ - u8 hash[SHA256_MAC_LEN]; - const u8 *addr[2]; - size_t len[2]; - - if (wps->last_msg == NULL) { - wpa_printf(MSG_DEBUG, "WPS: Last message not available for " - "building authenticator"); - return -1; - } - - /* Authenticator = HMAC-SHA256_AuthKey(M_prev || M_curr*) - * (M_curr* is M_curr without the Authenticator attribute) - */ - addr[0] = wpabuf_head(wps->last_msg); - len[0] = wpabuf_len(wps->last_msg); - addr[1] = wpabuf_head(msg); - len[1] = wpabuf_len(msg); - hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash); - - wpa_printf(MSG_DEBUG, "WPS: * Authenticator"); - wpabuf_put_be16(msg, ATTR_AUTHENTICATOR); - wpabuf_put_be16(msg, WPS_AUTHENTICATOR_LEN); - wpabuf_put_data(msg, hash, WPS_AUTHENTICATOR_LEN); - - return 0; -} - - -int wps_process_authenticator(struct wps_data *wps, const u8 *authenticator, - const struct wpabuf *msg) -{ - u8 hash[SHA256_MAC_LEN]; - const u8 *addr[2]; - size_t len[2]; - - if (authenticator == NULL) { - wpa_printf(MSG_DEBUG, "WPS: No Authenticator attribute " - "included"); - return -1; - } - - if (wps->last_msg == NULL) { - wpa_printf(MSG_DEBUG, "WPS: Last message not available for " - "validating authenticator"); - return -1; - } - - /* Authenticator = HMAC-SHA256_AuthKey(M_prev || M_curr*) - * (M_curr* is M_curr without the Authenticator attribute) - */ - addr[0] = wpabuf_head(wps->last_msg); - len[0] = wpabuf_len(wps->last_msg); - addr[1] = wpabuf_head(msg); - len[1] = wpabuf_len(msg) - 4 - WPS_AUTHENTICATOR_LEN; - hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash); - - if (os_memcmp(hash, authenticator, WPS_AUTHENTICATOR_LEN) != 0) { - wpa_printf(MSG_DEBUG, "WPS: Incorrect Authenticator"); - return -1; - } - - return 0; -} - - void wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd, size_t dev_passwd_len) { @@ -701,371 +204,450 @@ struct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr, } -int wps_process_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg, - const u8 *key_wrap_auth) -{ - u8 hash[SHA256_MAC_LEN]; - const u8 *head; - size_t len; - - if (key_wrap_auth == NULL) { - wpa_printf(MSG_DEBUG, "WPS: No KWA in decrypted attribute"); - return -1; - } - - head = wpabuf_head(msg); - len = wpabuf_len(msg) - 4 - WPS_KWA_LEN; - if (head + len != key_wrap_auth - 4) { - wpa_printf(MSG_DEBUG, "WPS: KWA not in the end of the " - "decrypted attribute"); - return -1; - } - - hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, head, len, hash); - if (os_memcmp(hash, key_wrap_auth, WPS_KWA_LEN) != 0) { - wpa_printf(MSG_DEBUG, "WPS: Invalid KWA"); - return -1; +/** + * wps_pin_checksum - Compute PIN checksum + * @pin: Seven digit PIN (i.e., eight digit PIN without the checksum digit) + * Returns: Checksum digit + */ +unsigned int wps_pin_checksum(unsigned int pin) +{ + unsigned int accum = 0; + while (pin) { + accum += 3 * (pin % 10); + pin /= 10; + accum += pin % 10; + pin /= 10; } - return 0; + return (10 - accum % 10) % 10; } -int wps_build_version(struct wpabuf *msg) +/** + * wps_pin_valid - Check whether a PIN has a valid checksum + * @pin: Eight digit PIN (i.e., including the checksum digit) + * Returns: 1 if checksum digit is valid, or 0 if not + */ +unsigned int wps_pin_valid(unsigned int pin) { - wpa_printf(MSG_DEBUG, "WPS: * Version"); - wpabuf_put_be16(msg, ATTR_VERSION); - wpabuf_put_be16(msg, 1); - wpabuf_put_u8(msg, WPS_VERSION); - return 0; + return wps_pin_checksum(pin / 10) == (pin % 10); } -int wps_build_msg_type(struct wpabuf *msg, enum wps_msg_type msg_type) +/** + * wps_generate_pin - Generate a random PIN + * Returns: Eight digit PIN (i.e., including the checksum digit) + */ +unsigned int wps_generate_pin(void) { - wpa_printf(MSG_DEBUG, "WPS: * Message Type (%d)", msg_type); - wpabuf_put_be16(msg, ATTR_MSG_TYPE); - wpabuf_put_be16(msg, 1); - wpabuf_put_u8(msg, msg_type); - return 0; -} + unsigned int val; + /* Generate seven random digits for the PIN */ + if (os_get_random((unsigned char *) &val, sizeof(val)) < 0) { + struct os_time now; + os_get_time(&now); + val = os_random() ^ now.sec ^ now.usec; + } + val %= 10000000; -int wps_build_enrollee_nonce(struct wps_data *wps, struct wpabuf *msg) -{ - wpa_printf(MSG_DEBUG, "WPS: * Enrollee Nonce"); - wpabuf_put_be16(msg, ATTR_ENROLLEE_NONCE); - wpabuf_put_be16(msg, WPS_NONCE_LEN); - wpabuf_put_data(msg, wps->nonce_e, WPS_NONCE_LEN); - return 0; + /* Append checksum digit */ + return val * 10 + wps_pin_checksum(val); } -int wps_build_registrar_nonce(struct wps_data *wps, struct wpabuf *msg) +void wps_fail_event(struct wps_context *wps, enum wps_msg_type msg) { - wpa_printf(MSG_DEBUG, "WPS: * Registrar Nonce"); - wpabuf_put_be16(msg, ATTR_REGISTRAR_NONCE); - wpabuf_put_be16(msg, WPS_NONCE_LEN); - wpabuf_put_data(msg, wps->nonce_r, WPS_NONCE_LEN); - return 0; -} + union wps_event_data data; + if (wps->event_cb == NULL) + return; -int wps_build_auth_type_flags(struct wps_data *wps, struct wpabuf *msg) -{ - wpa_printf(MSG_DEBUG, "WPS: * Authentication Type Flags"); - wpabuf_put_be16(msg, ATTR_AUTH_TYPE_FLAGS); - wpabuf_put_be16(msg, 2); - wpabuf_put_be16(msg, WPS_AUTH_TYPES); - return 0; + os_memset(&data, 0, sizeof(data)); + data.fail.msg = msg; + wps->event_cb(wps->cb_ctx, WPS_EV_FAIL, &data); } -int wps_build_encr_type_flags(struct wps_data *wps, struct wpabuf *msg) +void wps_success_event(struct wps_context *wps) { - wpa_printf(MSG_DEBUG, "WPS: * Encryption Type Flags"); - wpabuf_put_be16(msg, ATTR_ENCR_TYPE_FLAGS); - wpabuf_put_be16(msg, 2); - wpabuf_put_be16(msg, WPS_ENCR_TYPES); - return 0; + if (wps->event_cb == NULL) + return; + + wps->event_cb(wps->cb_ctx, WPS_EV_SUCCESS, NULL); } -int wps_build_conn_type_flags(struct wps_data *wps, struct wpabuf *msg) +void wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part) { - wpa_printf(MSG_DEBUG, "WPS: * Connection Type Flags"); - wpabuf_put_be16(msg, ATTR_CONN_TYPE_FLAGS); - wpabuf_put_be16(msg, 1); - wpabuf_put_u8(msg, WPS_CONN_ESS); - return 0; -} + union wps_event_data data; + if (wps->event_cb == NULL) + return; -int wps_build_assoc_state(struct wps_data *wps, struct wpabuf *msg) -{ - wpa_printf(MSG_DEBUG, "WPS: * Association State"); - wpabuf_put_be16(msg, ATTR_ASSOC_STATE); - wpabuf_put_be16(msg, 2); - wpabuf_put_be16(msg, WPS_ASSOC_NOT_ASSOC); - return 0; + os_memset(&data, 0, sizeof(data)); + data.pwd_auth_fail.enrollee = enrollee; + data.pwd_auth_fail.part = part; + wps->event_cb(wps->cb_ctx, WPS_EV_PWD_AUTH_FAIL, &data); } -int wps_build_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg) +void wps_pbc_overlap_event(struct wps_context *wps) { - u8 hash[SHA256_MAC_LEN]; + if (wps->event_cb == NULL) + return; - wpa_printf(MSG_DEBUG, "WPS: * Key Wrap Authenticator"); - hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, wpabuf_head(msg), - wpabuf_len(msg), hash); - - wpabuf_put_be16(msg, ATTR_KEY_WRAP_AUTH); - wpabuf_put_be16(msg, WPS_KWA_LEN); - wpabuf_put_data(msg, hash, WPS_KWA_LEN); - return 0; + wps->event_cb(wps->cb_ctx, WPS_EV_PBC_OVERLAP, NULL); } -int wps_build_encr_settings(struct wps_data *wps, struct wpabuf *msg, - struct wpabuf *plain) +void wps_pbc_timeout_event(struct wps_context *wps) { - size_t pad_len; - const size_t block_size = 16; - u8 *iv, *data; + if (wps->event_cb == NULL) + return; - wpa_printf(MSG_DEBUG, "WPS: * Encrypted Settings"); + wps->event_cb(wps->cb_ctx, WPS_EV_PBC_TIMEOUT, NULL); +} - /* PKCS#5 v2.0 pad */ - pad_len = block_size - wpabuf_len(plain) % block_size; - os_memset(wpabuf_put(plain, pad_len), pad_len, pad_len); - wpabuf_put_be16(msg, ATTR_ENCR_SETTINGS); - wpabuf_put_be16(msg, block_size + wpabuf_len(plain)); +#ifdef CONFIG_WPS_OOB - iv = wpabuf_put(msg, block_size); - if (os_get_random(iv, block_size) < 0) - return -1; +static struct wpabuf * wps_get_oob_cred(struct wps_context *wps) +{ + struct wps_data data; + struct wpabuf *plain; - data = wpabuf_put(msg, 0); - wpabuf_put_buf(msg, plain); - if (aes_128_cbc_encrypt(wps->keywrapkey, iv, data, wpabuf_len(plain))) - return -1; + plain = wpabuf_alloc(500); + if (plain == NULL) { + wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB " + "credential"); + return NULL; + } - return 0; + os_memset(&data, 0, sizeof(data)); + data.wps = wps; + data.auth_type = wps->auth_types; + data.encr_type = wps->encr_types; + if (wps_build_version(plain) || + wps_build_cred(&data, plain) || + wps_build_wfa_ext(plain, 0, NULL, 0)) { + wpabuf_free(plain); + return NULL; + } + + return plain; } -static int wps_process_cred_network_idx(struct wps_credential *cred, - const u8 *idx) +static struct wpabuf * wps_get_oob_dev_pwd(struct wps_context *wps) { - if (idx == NULL) { - wpa_printf(MSG_DEBUG, "WPS: Credential did not include " - "Network Index"); - return -1; + struct wpabuf *data; + + data = wpabuf_alloc(9 + WPS_OOB_DEVICE_PASSWORD_ATTR_LEN); + if (data == NULL) { + wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB " + "device password attribute"); + return NULL; } - wpa_printf(MSG_DEBUG, "WPS: Network Index: %d", *idx); + wpabuf_free(wps->oob_conf.dev_password); + wps->oob_conf.dev_password = + wpabuf_alloc(WPS_OOB_DEVICE_PASSWORD_LEN * 2 + 1); + if (wps->oob_conf.dev_password == NULL) { + wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB " + "device password"); + wpabuf_free(data); + return NULL; + } - return 0; + if (wps_build_version(data) || + wps_build_oob_dev_password(data, wps) || + wps_build_wfa_ext(data, 0, NULL, 0)) { + wpa_printf(MSG_ERROR, "WPS: Build OOB device password " + "attribute error"); + wpabuf_free(data); + return NULL; + } + + return data; } -static int wps_process_cred_ssid(struct wps_credential *cred, const u8 *ssid, - size_t ssid_len) +static int wps_parse_oob_dev_pwd(struct wps_context *wps, + struct wpabuf *data) { - if (ssid == NULL) { - wpa_printf(MSG_DEBUG, "WPS: Credential did not include SSID"); + struct oob_conf_data *oob_conf = &wps->oob_conf; + struct wps_parse_attr attr; + const u8 *pos; + + if (wps_parse_msg(data, &attr) < 0 || + attr.oob_dev_password == NULL) { + wpa_printf(MSG_ERROR, "WPS: OOB device password not found"); return -1; } - /* Remove zero-padding since some Registrar implementations seem to use - * hardcoded 32-octet length for this attribute */ - while (ssid_len > 0 && ssid[ssid_len - 1] == 0) - ssid_len--; + pos = attr.oob_dev_password; - wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", ssid, ssid_len); - if (ssid_len <= sizeof(cred->ssid)) { - os_memcpy(cred->ssid, ssid, ssid_len); - cred->ssid_len = ssid_len; + oob_conf->pubkey_hash = + wpabuf_alloc_copy(pos, WPS_OOB_PUBKEY_HASH_LEN); + if (oob_conf->pubkey_hash == NULL) { + wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB " + "public key hash"); + return -1; } + pos += WPS_OOB_PUBKEY_HASH_LEN; - return 0; -} + wps->oob_dev_pw_id = WPA_GET_BE16(pos); + pos += sizeof(wps->oob_dev_pw_id); - -static int wps_process_cred_auth_type(struct wps_credential *cred, - const u8 *auth_type) -{ - if (auth_type == NULL) { - wpa_printf(MSG_DEBUG, "WPS: Credential did not include " - "Authentication Type"); + oob_conf->dev_password = + wpabuf_alloc(WPS_OOB_DEVICE_PASSWORD_LEN * 2 + 1); + if (oob_conf->dev_password == NULL) { + wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB " + "device password"); return -1; } - - cred->auth_type = WPA_GET_BE16(auth_type); - wpa_printf(MSG_DEBUG, "WPS: Authentication Type: 0x%x", - cred->auth_type); + wpa_snprintf_hex_uppercase(wpabuf_put(oob_conf->dev_password, + wpabuf_size(oob_conf->dev_password)), + wpabuf_size(oob_conf->dev_password), pos, + WPS_OOB_DEVICE_PASSWORD_LEN); return 0; } -static int wps_process_cred_encr_type(struct wps_credential *cred, - const u8 *encr_type) +static int wps_parse_oob_cred(struct wps_context *wps, struct wpabuf *data) { - if (encr_type == NULL) { - wpa_printf(MSG_DEBUG, "WPS: Credential did not include " - "Encryption Type"); + struct wpabuf msg; + struct wps_parse_attr attr; + size_t i; + + if (wps_parse_msg(data, &attr) < 0 || attr.num_cred <= 0) { + wpa_printf(MSG_ERROR, "WPS: OOB credential not found"); return -1; } - cred->encr_type = WPA_GET_BE16(encr_type); - wpa_printf(MSG_DEBUG, "WPS: Encryption Type: 0x%x", - cred->encr_type); + for (i = 0; i < attr.num_cred; i++) { + struct wps_credential local_cred; + struct wps_parse_attr cattr; + + os_memset(&local_cred, 0, sizeof(local_cred)); + wpabuf_set(&msg, attr.cred[i], attr.cred_len[i]); + if (wps_parse_msg(&msg, &cattr) < 0 || + wps_process_cred(&cattr, &local_cred)) { + wpa_printf(MSG_ERROR, "WPS: Failed to parse OOB " + "credential"); + return -1; + } + wps->cred_cb(wps->cb_ctx, &local_cred); + } return 0; } -static int wps_process_cred_network_key_idx(struct wps_credential *cred, - const u8 *key_idx) +int wps_process_oob(struct wps_context *wps, struct oob_device_data *oob_dev, + int registrar) { - if (key_idx == NULL) - return 0; /* optional attribute */ - - wpa_printf(MSG_DEBUG, "WPS: Network Key Index: %d", *key_idx); - cred->key_idx = *key_idx; + struct wpabuf *data; + int ret, write_f, oob_method = wps->oob_conf.oob_method; + void *oob_priv; - return 0; -} + write_f = oob_method == OOB_METHOD_DEV_PWD_E ? !registrar : registrar; - -static int wps_process_cred_network_key(struct wps_credential *cred, - const u8 *key, size_t key_len) -{ - if (key == NULL) { - wpa_printf(MSG_DEBUG, "WPS: Credential did not include " - "Network Key"); + oob_priv = oob_dev->init_func(wps, oob_dev, registrar); + if (oob_priv == NULL) { + wpa_printf(MSG_ERROR, "WPS: Failed to initialize OOB device"); return -1; } - wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key", key, key_len); - if (key_len <= sizeof(cred->key)) { - os_memcpy(cred->key, key, key_len); - cred->key_len = key_len; - } - - return 0; -} + if (write_f) { + if (oob_method == OOB_METHOD_CRED) + data = wps_get_oob_cred(wps); + else + data = wps_get_oob_dev_pwd(wps); + ret = 0; + if (data == NULL || oob_dev->write_func(oob_priv, data) < 0) + ret = -1; + } else { + data = oob_dev->read_func(oob_priv); + if (data == NULL) + ret = -1; + else { + if (oob_method == OOB_METHOD_CRED) + ret = wps_parse_oob_cred(wps, data); + else + ret = wps_parse_oob_dev_pwd(wps, data); + } + } + wpabuf_free(data); + oob_dev->deinit_func(oob_priv); -static int wps_process_cred_mac_addr(struct wps_credential *cred, - const u8 *mac_addr) -{ - if (mac_addr == NULL) { - wpa_printf(MSG_DEBUG, "WPS: Credential did not include " - "MAC Address"); + if (ret < 0) { + wpa_printf(MSG_ERROR, "WPS: Failed to process OOB data"); return -1; } - wpa_printf(MSG_DEBUG, "WPS: MAC Address " MACSTR, MAC2STR(mac_addr)); - os_memcpy(cred->mac_addr, mac_addr, ETH_ALEN); - return 0; } -static int wps_process_cred_eap_type(struct wps_credential *cred, - const u8 *eap_type, size_t eap_type_len) +struct oob_device_data * wps_get_oob_device(char *device_type) { - if (eap_type == NULL) - return 0; /* optional attribute */ +#ifdef CONFIG_WPS_UFD + if (os_strstr(device_type, "ufd") != NULL) + return &oob_ufd_device_data; +#endif /* CONFIG_WPS_UFD */ +#ifdef CONFIG_WPS_NFC + if (os_strstr(device_type, "nfc") != NULL) + return &oob_nfc_device_data; +#endif /* CONFIG_WPS_NFC */ - wpa_hexdump(MSG_DEBUG, "WPS: EAP Type", eap_type, eap_type_len); - - return 0; + return NULL; } -static int wps_process_cred_eap_identity(struct wps_credential *cred, - const u8 *identity, - size_t identity_len) +#ifdef CONFIG_WPS_NFC +struct oob_nfc_device_data * wps_get_oob_nfc_device(char *device_name) { - if (identity == NULL) - return 0; /* optional attribute */ - - wpa_hexdump_ascii(MSG_DEBUG, "WPS: EAP Identity", - identity, identity_len); + if (device_name == NULL) + return NULL; +#ifdef CONFIG_WPS_NFC_PN531 + if (os_strstr(device_name, "pn531") != NULL) + return &oob_nfc_pn531_device_data; +#endif /* CONFIG_WPS_NFC_PN531 */ - return 0; + return NULL; } +#endif /* CONFIG_WPS_NFC */ -static int wps_process_cred_key_prov_auto(struct wps_credential *cred, - const u8 *key_prov_auto) +int wps_get_oob_method(char *method) { - if (key_prov_auto == NULL) - return 0; /* optional attribute */ - - wpa_printf(MSG_DEBUG, "WPS: Key Provided Automatically: %d", - *key_prov_auto); - - return 0; + if (os_strstr(method, "pin-e") != NULL) + return OOB_METHOD_DEV_PWD_E; + if (os_strstr(method, "pin-r") != NULL) + return OOB_METHOD_DEV_PWD_R; + if (os_strstr(method, "cred") != NULL) + return OOB_METHOD_CRED; + return OOB_METHOD_UNKNOWN; } +#endif /* CONFIG_WPS_OOB */ -static int wps_process_cred_802_1x_enabled(struct wps_credential *cred, - const u8 *dot1x_enabled) + +int wps_dev_type_str2bin(const char *str, u8 dev_type[WPS_DEV_TYPE_LEN]) { - if (dot1x_enabled == NULL) - return 0; /* optional attribute */ + const char *pos; + + /* -- */ + WPA_PUT_BE16(dev_type, atoi(str)); + pos = os_strchr(str, '-'); + if (pos == NULL) + return -1; + pos++; + if (hexstr2bin(pos, &dev_type[2], 4)) + return -1; + pos = os_strchr(pos, '-'); + if (pos == NULL) + return -1; + pos++; + WPA_PUT_BE16(&dev_type[6], atoi(pos)); - wpa_printf(MSG_DEBUG, "WPS: 802.1X Enabled: %d", *dot1x_enabled); return 0; } -int wps_process_cred(struct wps_parse_attr *attr, - struct wps_credential *cred) +char * wps_dev_type_bin2str(const u8 dev_type[WPS_DEV_TYPE_LEN], char *buf, + size_t buf_len) { - wpa_printf(MSG_DEBUG, "WPS: Process Credential"); - - /* TODO: support multiple Network Keys */ - if (wps_process_cred_network_idx(cred, attr->network_idx) || - wps_process_cred_ssid(cred, attr->ssid, attr->ssid_len) || - wps_process_cred_auth_type(cred, attr->auth_type) || - wps_process_cred_encr_type(cred, attr->encr_type) || - wps_process_cred_network_key_idx(cred, attr->network_key_idx) || - wps_process_cred_network_key(cred, attr->network_key, - attr->network_key_len) || - wps_process_cred_mac_addr(cred, attr->mac_addr) || - wps_process_cred_eap_type(cred, attr->eap_type, - attr->eap_type_len) || - wps_process_cred_eap_identity(cred, attr->eap_identity, - attr->eap_identity_len) || - wps_process_cred_key_prov_auto(cred, attr->key_prov_auto) || - wps_process_cred_802_1x_enabled(cred, attr->dot1x_enabled)) - return -1; + int ret; - return 0; + ret = os_snprintf(buf, buf_len, "%u-%08X-%u", + WPA_GET_BE16(dev_type), WPA_GET_BE32(&dev_type[2]), + WPA_GET_BE16(&dev_type[6])); + if (ret < 0 || (unsigned int) ret >= buf_len) + return NULL; + + return buf; } -int wps_process_ap_settings(struct wps_parse_attr *attr, - struct wps_credential *cred) +void uuid_gen_mac_addr(const u8 *mac_addr, u8 *uuid) { - wpa_printf(MSG_DEBUG, "WPS: Processing AP Settings"); - os_memset(cred, 0, sizeof(*cred)); - /* TODO: optional attributes New Password and Device Password ID */ - if (wps_process_cred_ssid(cred, attr->ssid, attr->ssid_len) || - wps_process_cred_auth_type(cred, attr->auth_type) || - wps_process_cred_encr_type(cred, attr->encr_type) || - wps_process_cred_network_key_idx(cred, attr->network_key_idx) || - wps_process_cred_network_key(cred, attr->network_key, - attr->network_key_len) || - wps_process_cred_mac_addr(cred, attr->mac_addr)) - return -1; + const u8 *addr[2]; + size_t len[2]; + u8 hash[SHA1_MAC_LEN]; + u8 nsid[16] = { + 0x52, 0x64, 0x80, 0xf8, + 0xc9, 0x9b, + 0x4b, 0xe5, + 0xa6, 0x55, + 0x58, 0xed, 0x5f, 0x5d, 0x60, 0x84 + }; + + addr[0] = nsid; + len[0] = sizeof(nsid); + addr[1] = mac_addr; + len[1] = 6; + sha1_vector(2, addr, len, hash); + os_memcpy(uuid, hash, 16); + + /* Version: 5 = named-based version using SHA-1 */ + uuid[6] = (5 << 4) | (uuid[6] & 0x0f); + + /* Variant specified in RFC 4122 */ + uuid[8] = 0x80 | (uuid[8] & 0x3f); +} + + +u16 wps_config_methods_str2bin(const char *str) +{ + u16 methods = 0; + + if (str == NULL) { + /* Default to enabling methods based on build configuration */ + methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD; +#ifdef CONFIG_WPS2 + methods |= WPS_CONFIG_VIRT_DISPLAY; +#endif /* CONFIG_WPS2 */ +#ifdef CONFIG_WPS_UFD + methods |= WPS_CONFIG_USBA; +#endif /* CONFIG_WPS_UFD */ +#ifdef CONFIG_WPS_NFC + methods |= WPS_CONFIG_NFC_INTERFACE; +#endif /* CONFIG_WPS_NFC */ + } else { + if (os_strstr(str, "usba")) + methods |= WPS_CONFIG_USBA; + if (os_strstr(str, "ethernet")) + methods |= WPS_CONFIG_ETHERNET; + if (os_strstr(str, "label")) + methods |= WPS_CONFIG_LABEL; + if (os_strstr(str, "display")) + methods |= WPS_CONFIG_DISPLAY; + if (os_strstr(str, "ext_nfc_token")) + methods |= WPS_CONFIG_EXT_NFC_TOKEN; + if (os_strstr(str, "int_nfc_token")) + methods |= WPS_CONFIG_INT_NFC_TOKEN; + if (os_strstr(str, "nfc_interface")) + methods |= WPS_CONFIG_NFC_INTERFACE; + if (os_strstr(str, "push_button")) + methods |= WPS_CONFIG_PUSHBUTTON; + if (os_strstr(str, "keypad")) + methods |= WPS_CONFIG_KEYPAD; +#ifdef CONFIG_WPS2 + if (os_strstr(str, "virtual_display")) + methods |= WPS_CONFIG_VIRT_DISPLAY; + if (os_strstr(str, "physical_display")) + methods |= WPS_CONFIG_PHY_DISPLAY; + if (os_strstr(str, "virtual_push_button")) + methods |= WPS_CONFIG_VIRT_PUSHBUTTON; + if (os_strstr(str, "physical_push_button")) + methods |= WPS_CONFIG_PHY_PUSHBUTTON; +#endif /* CONFIG_WPS2 */ + } - return 0; + return methods; }