b3ddab2122
WPS spec is not very specific on the presentation used for the DH values. The Public Key attribute is described to be 192 octets long, so that could be interpreted to imply that other places use fixed length presentation for the DH keys. Change the DH derivation to use fixed length bufferd by zero padding them from beginning if needed. This can resolve infrequent (about 1/256 chance for both Public Key and Shared Key being shorter) interop issues.
254 lines
6.2 KiB
C
254 lines
6.2 KiB
C
/*
|
|
* Wi-Fi Protected Setup - attribute building
|
|
* Copyright (c) 2008, 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
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* Alternatively, this software may be distributed under the terms of BSD
|
|
* license.
|
|
*
|
|
* See README and COPYING for more details.
|
|
*/
|
|
|
|
#include "includes.h"
|
|
|
|
#include "common.h"
|
|
#include "dh_groups.h"
|
|
#include "sha256.h"
|
|
#include "aes_wrap.h"
|
|
#include "wps_i.h"
|
|
|
|
|
|
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);
|
|
pubkey = wpabuf_zeropad(pubkey, 192);
|
|
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_build_req_type(struct wpabuf *msg, enum wps_request_type type)
|
|
{
|
|
wpa_printf(MSG_DEBUG, "WPS: * Request Type");
|
|
wpabuf_put_be16(msg, ATTR_REQUEST_TYPE);
|
|
wpabuf_put_be16(msg, 1);
|
|
wpabuf_put_u8(msg, type);
|
|
return 0;
|
|
}
|
|
|
|
|
|
int wps_build_config_methods(struct wpabuf *msg, u16 methods)
|
|
{
|
|
wpa_printf(MSG_DEBUG, "WPS: * Config Methods (%x)", methods);
|
|
wpabuf_put_be16(msg, ATTR_CONFIG_METHODS);
|
|
wpabuf_put_be16(msg, 2);
|
|
wpabuf_put_be16(msg, methods);
|
|
return 0;
|
|
}
|
|
|
|
|
|
int wps_build_uuid_e(struct wpabuf *msg, const u8 *uuid)
|
|
{
|
|
wpa_printf(MSG_DEBUG, "WPS: * UUID-E");
|
|
wpabuf_put_be16(msg, ATTR_UUID_E);
|
|
wpabuf_put_be16(msg, WPS_UUID_LEN);
|
|
wpabuf_put_data(msg, uuid, WPS_UUID_LEN);
|
|
return 0;
|
|
}
|
|
|
|
|
|
int wps_build_dev_password_id(struct wpabuf *msg, u16 id)
|
|
{
|
|
wpa_printf(MSG_DEBUG, "WPS: * Device Password ID (%d)", id);
|
|
wpabuf_put_be16(msg, ATTR_DEV_PASSWORD_ID);
|
|
wpabuf_put_be16(msg, 2);
|
|
wpabuf_put_be16(msg, id);
|
|
return 0;
|
|
}
|
|
|
|
|
|
int wps_build_config_error(struct wpabuf *msg, u16 err)
|
|
{
|
|
wpa_printf(MSG_DEBUG, "WPS: * Configuration Error (%d)", err);
|
|
wpabuf_put_be16(msg, ATTR_CONFIG_ERROR);
|
|
wpabuf_put_be16(msg, 2);
|
|
wpabuf_put_be16(msg, err);
|
|
return 0;
|
|
}
|
|
|
|
|
|
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_build_version(struct wpabuf *msg)
|
|
{
|
|
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;
|
|
}
|
|
|
|
|
|
int wps_build_msg_type(struct wpabuf *msg, enum wps_msg_type msg_type)
|
|
{
|
|
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;
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
int wps_build_registrar_nonce(struct wps_data *wps, struct wpabuf *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;
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
int wps_build_encr_type_flags(struct wps_data *wps, struct wpabuf *msg)
|
|
{
|
|
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;
|
|
}
|
|
|
|
|
|
int wps_build_conn_type_flags(struct wps_data *wps, struct wpabuf *msg)
|
|
{
|
|
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;
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
int wps_build_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg)
|
|
{
|
|
u8 hash[SHA256_MAC_LEN];
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
int wps_build_encr_settings(struct wps_data *wps, struct wpabuf *msg,
|
|
struct wpabuf *plain)
|
|
{
|
|
size_t pad_len;
|
|
const size_t block_size = 16;
|
|
u8 *iv, *data;
|
|
|
|
wpa_printf(MSG_DEBUG, "WPS: * Encrypted Settings");
|
|
|
|
/* 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));
|
|
|
|
iv = wpabuf_put(msg, block_size);
|
|
if (os_get_random(iv, block_size) < 0)
|
|
return -1;
|
|
|
|
data = wpabuf_put(msg, 0);
|
|
wpabuf_put_buf(msg, plain);
|
|
if (aes_128_cbc_encrypt(wps->keywrapkey, iv, data, wpabuf_len(plain)))
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|