/*
* Wi-Fi Protected Setup - common functionality
- * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi>
*
* 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
#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;
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;
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;
}
-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;
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;
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);
}
-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)
{
}
-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;
+
+ /* <categ>-<OUI>-<subcateg> */
+ 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;
}