1189251Ssam/* 2189251Ssam * Wi-Fi Protected Setup - attribute building 3189251Ssam * Copyright (c) 2008, 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/sha256.h" 22189251Ssam#include "wps_i.h" 23189251Ssam 24189251Ssam 25189251Ssamint wps_build_public_key(struct wps_data *wps, struct wpabuf *msg) 26189251Ssam{ 27189251Ssam struct wpabuf *pubkey; 28189251Ssam 29189251Ssam wpa_printf(MSG_DEBUG, "WPS: * Public Key"); 30214734Srpaulo wpabuf_free(wps->dh_privkey); 31214734Srpaulo if (wps->dev_pw_id != DEV_PW_DEFAULT && wps->wps->dh_privkey) { 32214734Srpaulo wpa_printf(MSG_DEBUG, "WPS: Using pre-configured DH keys"); 33214734Srpaulo wps->dh_privkey = wpabuf_dup(wps->wps->dh_privkey); 34214734Srpaulo wps->dh_ctx = wps->wps->dh_ctx; 35214734Srpaulo wps->wps->dh_ctx = NULL; 36214734Srpaulo pubkey = wpabuf_dup(wps->wps->dh_pubkey); 37214734Srpaulo } else { 38214734Srpaulo wpa_printf(MSG_DEBUG, "WPS: Generate new DH keys"); 39214734Srpaulo wps->dh_privkey = NULL; 40214734Srpaulo dh5_free(wps->dh_ctx); 41214734Srpaulo wps->dh_ctx = dh5_init(&wps->dh_privkey, &pubkey); 42214734Srpaulo pubkey = wpabuf_zeropad(pubkey, 192); 43214734Srpaulo } 44214734Srpaulo if (wps->dh_ctx == NULL || wps->dh_privkey == NULL || pubkey == NULL) { 45189251Ssam wpa_printf(MSG_DEBUG, "WPS: Failed to initialize " 46189251Ssam "Diffie-Hellman handshake"); 47214734Srpaulo wpabuf_free(pubkey); 48189251Ssam return -1; 49189251Ssam } 50189251Ssam 51189251Ssam wpabuf_put_be16(msg, ATTR_PUBLIC_KEY); 52189251Ssam wpabuf_put_be16(msg, wpabuf_len(pubkey)); 53189251Ssam wpabuf_put_buf(msg, pubkey); 54189251Ssam 55189251Ssam if (wps->registrar) { 56189251Ssam wpabuf_free(wps->dh_pubkey_r); 57189251Ssam wps->dh_pubkey_r = pubkey; 58189251Ssam } else { 59189251Ssam wpabuf_free(wps->dh_pubkey_e); 60189251Ssam wps->dh_pubkey_e = pubkey; 61189251Ssam } 62189251Ssam 63189251Ssam return 0; 64189251Ssam} 65189251Ssam 66189251Ssam 67189251Ssamint wps_build_req_type(struct wpabuf *msg, enum wps_request_type type) 68189251Ssam{ 69189251Ssam wpa_printf(MSG_DEBUG, "WPS: * Request Type"); 70189251Ssam wpabuf_put_be16(msg, ATTR_REQUEST_TYPE); 71189251Ssam wpabuf_put_be16(msg, 1); 72189251Ssam wpabuf_put_u8(msg, type); 73189251Ssam return 0; 74189251Ssam} 75189251Ssam 76189251Ssam 77214734Srpauloint wps_build_resp_type(struct wpabuf *msg, enum wps_response_type type) 78214734Srpaulo{ 79214734Srpaulo wpa_printf(MSG_DEBUG, "WPS: * Response Type (%d)", type); 80214734Srpaulo wpabuf_put_be16(msg, ATTR_RESPONSE_TYPE); 81214734Srpaulo wpabuf_put_be16(msg, 1); 82214734Srpaulo wpabuf_put_u8(msg, type); 83214734Srpaulo return 0; 84214734Srpaulo} 85214734Srpaulo 86214734Srpaulo 87189251Ssamint wps_build_config_methods(struct wpabuf *msg, u16 methods) 88189251Ssam{ 89189251Ssam wpa_printf(MSG_DEBUG, "WPS: * Config Methods (%x)", methods); 90189251Ssam wpabuf_put_be16(msg, ATTR_CONFIG_METHODS); 91189251Ssam wpabuf_put_be16(msg, 2); 92189251Ssam wpabuf_put_be16(msg, methods); 93189251Ssam return 0; 94189251Ssam} 95189251Ssam 96189251Ssam 97189251Ssamint wps_build_uuid_e(struct wpabuf *msg, const u8 *uuid) 98189251Ssam{ 99189251Ssam wpa_printf(MSG_DEBUG, "WPS: * UUID-E"); 100189251Ssam wpabuf_put_be16(msg, ATTR_UUID_E); 101189251Ssam wpabuf_put_be16(msg, WPS_UUID_LEN); 102189251Ssam wpabuf_put_data(msg, uuid, WPS_UUID_LEN); 103189251Ssam return 0; 104189251Ssam} 105189251Ssam 106189251Ssam 107189251Ssamint wps_build_dev_password_id(struct wpabuf *msg, u16 id) 108189251Ssam{ 109189251Ssam wpa_printf(MSG_DEBUG, "WPS: * Device Password ID (%d)", id); 110189251Ssam wpabuf_put_be16(msg, ATTR_DEV_PASSWORD_ID); 111189251Ssam wpabuf_put_be16(msg, 2); 112189251Ssam wpabuf_put_be16(msg, id); 113189251Ssam return 0; 114189251Ssam} 115189251Ssam 116189251Ssam 117189251Ssamint wps_build_config_error(struct wpabuf *msg, u16 err) 118189251Ssam{ 119189251Ssam wpa_printf(MSG_DEBUG, "WPS: * Configuration Error (%d)", err); 120189251Ssam wpabuf_put_be16(msg, ATTR_CONFIG_ERROR); 121189251Ssam wpabuf_put_be16(msg, 2); 122189251Ssam wpabuf_put_be16(msg, err); 123189251Ssam return 0; 124189251Ssam} 125189251Ssam 126189251Ssam 127189251Ssamint wps_build_authenticator(struct wps_data *wps, struct wpabuf *msg) 128189251Ssam{ 129189251Ssam u8 hash[SHA256_MAC_LEN]; 130189251Ssam const u8 *addr[2]; 131189251Ssam size_t len[2]; 132189251Ssam 133189251Ssam if (wps->last_msg == NULL) { 134189251Ssam wpa_printf(MSG_DEBUG, "WPS: Last message not available for " 135189251Ssam "building authenticator"); 136189251Ssam return -1; 137189251Ssam } 138189251Ssam 139189251Ssam /* Authenticator = HMAC-SHA256_AuthKey(M_prev || M_curr*) 140189251Ssam * (M_curr* is M_curr without the Authenticator attribute) 141189251Ssam */ 142189251Ssam addr[0] = wpabuf_head(wps->last_msg); 143189251Ssam len[0] = wpabuf_len(wps->last_msg); 144189251Ssam addr[1] = wpabuf_head(msg); 145189251Ssam len[1] = wpabuf_len(msg); 146189251Ssam hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash); 147189251Ssam 148189251Ssam wpa_printf(MSG_DEBUG, "WPS: * Authenticator"); 149189251Ssam wpabuf_put_be16(msg, ATTR_AUTHENTICATOR); 150189251Ssam wpabuf_put_be16(msg, WPS_AUTHENTICATOR_LEN); 151189251Ssam wpabuf_put_data(msg, hash, WPS_AUTHENTICATOR_LEN); 152189251Ssam 153189251Ssam return 0; 154189251Ssam} 155189251Ssam 156189251Ssam 157189251Ssamint wps_build_version(struct wpabuf *msg) 158189251Ssam{ 159189251Ssam wpa_printf(MSG_DEBUG, "WPS: * Version"); 160189251Ssam wpabuf_put_be16(msg, ATTR_VERSION); 161189251Ssam wpabuf_put_be16(msg, 1); 162189251Ssam wpabuf_put_u8(msg, WPS_VERSION); 163189251Ssam return 0; 164189251Ssam} 165189251Ssam 166189251Ssam 167189251Ssamint wps_build_msg_type(struct wpabuf *msg, enum wps_msg_type msg_type) 168189251Ssam{ 169189251Ssam wpa_printf(MSG_DEBUG, "WPS: * Message Type (%d)", msg_type); 170189251Ssam wpabuf_put_be16(msg, ATTR_MSG_TYPE); 171189251Ssam wpabuf_put_be16(msg, 1); 172189251Ssam wpabuf_put_u8(msg, msg_type); 173189251Ssam return 0; 174189251Ssam} 175189251Ssam 176189251Ssam 177189251Ssamint wps_build_enrollee_nonce(struct wps_data *wps, struct wpabuf *msg) 178189251Ssam{ 179189251Ssam wpa_printf(MSG_DEBUG, "WPS: * Enrollee Nonce"); 180189251Ssam wpabuf_put_be16(msg, ATTR_ENROLLEE_NONCE); 181189251Ssam wpabuf_put_be16(msg, WPS_NONCE_LEN); 182189251Ssam wpabuf_put_data(msg, wps->nonce_e, WPS_NONCE_LEN); 183189251Ssam return 0; 184189251Ssam} 185189251Ssam 186189251Ssam 187189251Ssamint wps_build_registrar_nonce(struct wps_data *wps, struct wpabuf *msg) 188189251Ssam{ 189189251Ssam wpa_printf(MSG_DEBUG, "WPS: * Registrar Nonce"); 190189251Ssam wpabuf_put_be16(msg, ATTR_REGISTRAR_NONCE); 191189251Ssam wpabuf_put_be16(msg, WPS_NONCE_LEN); 192189251Ssam wpabuf_put_data(msg, wps->nonce_r, WPS_NONCE_LEN); 193189251Ssam return 0; 194189251Ssam} 195189251Ssam 196189251Ssam 197189251Ssamint wps_build_auth_type_flags(struct wps_data *wps, struct wpabuf *msg) 198189251Ssam{ 199189251Ssam wpa_printf(MSG_DEBUG, "WPS: * Authentication Type Flags"); 200189251Ssam wpabuf_put_be16(msg, ATTR_AUTH_TYPE_FLAGS); 201189251Ssam wpabuf_put_be16(msg, 2); 202189251Ssam wpabuf_put_be16(msg, WPS_AUTH_TYPES); 203189251Ssam return 0; 204189251Ssam} 205189251Ssam 206189251Ssam 207189251Ssamint wps_build_encr_type_flags(struct wps_data *wps, struct wpabuf *msg) 208189251Ssam{ 209189251Ssam wpa_printf(MSG_DEBUG, "WPS: * Encryption Type Flags"); 210189251Ssam wpabuf_put_be16(msg, ATTR_ENCR_TYPE_FLAGS); 211189251Ssam wpabuf_put_be16(msg, 2); 212189251Ssam wpabuf_put_be16(msg, WPS_ENCR_TYPES); 213189251Ssam return 0; 214189251Ssam} 215189251Ssam 216189251Ssam 217189251Ssamint wps_build_conn_type_flags(struct wps_data *wps, struct wpabuf *msg) 218189251Ssam{ 219189251Ssam wpa_printf(MSG_DEBUG, "WPS: * Connection Type Flags"); 220189251Ssam wpabuf_put_be16(msg, ATTR_CONN_TYPE_FLAGS); 221189251Ssam wpabuf_put_be16(msg, 1); 222189251Ssam wpabuf_put_u8(msg, WPS_CONN_ESS); 223189251Ssam return 0; 224189251Ssam} 225189251Ssam 226189251Ssam 227189251Ssamint wps_build_assoc_state(struct wps_data *wps, struct wpabuf *msg) 228189251Ssam{ 229189251Ssam wpa_printf(MSG_DEBUG, "WPS: * Association State"); 230189251Ssam wpabuf_put_be16(msg, ATTR_ASSOC_STATE); 231189251Ssam wpabuf_put_be16(msg, 2); 232189251Ssam wpabuf_put_be16(msg, WPS_ASSOC_NOT_ASSOC); 233189251Ssam return 0; 234189251Ssam} 235189251Ssam 236189251Ssam 237189251Ssamint wps_build_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg) 238189251Ssam{ 239189251Ssam u8 hash[SHA256_MAC_LEN]; 240189251Ssam 241189251Ssam wpa_printf(MSG_DEBUG, "WPS: * Key Wrap Authenticator"); 242189251Ssam hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, wpabuf_head(msg), 243189251Ssam wpabuf_len(msg), hash); 244189251Ssam 245189251Ssam wpabuf_put_be16(msg, ATTR_KEY_WRAP_AUTH); 246189251Ssam wpabuf_put_be16(msg, WPS_KWA_LEN); 247189251Ssam wpabuf_put_data(msg, hash, WPS_KWA_LEN); 248189251Ssam return 0; 249189251Ssam} 250189251Ssam 251189251Ssam 252189251Ssamint wps_build_encr_settings(struct wps_data *wps, struct wpabuf *msg, 253189251Ssam struct wpabuf *plain) 254189251Ssam{ 255189251Ssam size_t pad_len; 256189251Ssam const size_t block_size = 16; 257189251Ssam u8 *iv, *data; 258189251Ssam 259189251Ssam wpa_printf(MSG_DEBUG, "WPS: * Encrypted Settings"); 260189251Ssam 261189251Ssam /* PKCS#5 v2.0 pad */ 262189251Ssam pad_len = block_size - wpabuf_len(plain) % block_size; 263189251Ssam os_memset(wpabuf_put(plain, pad_len), pad_len, pad_len); 264189251Ssam 265189251Ssam wpabuf_put_be16(msg, ATTR_ENCR_SETTINGS); 266189251Ssam wpabuf_put_be16(msg, block_size + wpabuf_len(plain)); 267189251Ssam 268189251Ssam iv = wpabuf_put(msg, block_size); 269189251Ssam if (os_get_random(iv, block_size) < 0) 270189251Ssam return -1; 271189251Ssam 272189251Ssam data = wpabuf_put(msg, 0); 273189251Ssam wpabuf_put_buf(msg, plain); 274189251Ssam if (aes_128_cbc_encrypt(wps->keywrapkey, iv, data, wpabuf_len(plain))) 275189251Ssam return -1; 276189251Ssam 277189251Ssam return 0; 278189251Ssam} 279214734Srpaulo 280214734Srpaulo 281214734Srpaulo#ifdef CONFIG_WPS_OOB 282214734Srpauloint wps_build_oob_dev_password(struct wpabuf *msg, struct wps_context *wps) 283214734Srpaulo{ 284214734Srpaulo size_t hash_len; 285214734Srpaulo const u8 *addr[1]; 286214734Srpaulo u8 pubkey_hash[WPS_HASH_LEN]; 287214734Srpaulo u8 dev_password_bin[WPS_OOB_DEVICE_PASSWORD_LEN]; 288214734Srpaulo 289214734Srpaulo wpa_printf(MSG_DEBUG, "WPS: * OOB Device Password"); 290214734Srpaulo 291214734Srpaulo addr[0] = wpabuf_head(wps->dh_pubkey); 292214734Srpaulo hash_len = wpabuf_len(wps->dh_pubkey); 293214734Srpaulo sha256_vector(1, addr, &hash_len, pubkey_hash); 294214734Srpaulo 295214734Srpaulo if (os_get_random((u8 *) &wps->oob_dev_pw_id, sizeof(u16)) < 0) { 296214734Srpaulo wpa_printf(MSG_ERROR, "WPS: device password id " 297214734Srpaulo "generation error"); 298214734Srpaulo return -1; 299214734Srpaulo } 300214734Srpaulo wps->oob_dev_pw_id |= 0x0010; 301214734Srpaulo 302214734Srpaulo if (os_get_random(dev_password_bin, WPS_OOB_DEVICE_PASSWORD_LEN) < 0) { 303214734Srpaulo wpa_printf(MSG_ERROR, "WPS: OOB device password " 304214734Srpaulo "generation error"); 305214734Srpaulo return -1; 306214734Srpaulo } 307214734Srpaulo 308214734Srpaulo wpabuf_put_be16(msg, ATTR_OOB_DEVICE_PASSWORD); 309214734Srpaulo wpabuf_put_be16(msg, WPS_OOB_DEVICE_PASSWORD_ATTR_LEN); 310214734Srpaulo wpabuf_put_data(msg, pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN); 311214734Srpaulo wpabuf_put_be16(msg, wps->oob_dev_pw_id); 312214734Srpaulo wpabuf_put_data(msg, dev_password_bin, WPS_OOB_DEVICE_PASSWORD_LEN); 313214734Srpaulo 314214734Srpaulo wpa_snprintf_hex_uppercase( 315214734Srpaulo wpabuf_put(wps->oob_conf.dev_password, 316214734Srpaulo wpabuf_size(wps->oob_conf.dev_password)), 317214734Srpaulo wpabuf_size(wps->oob_conf.dev_password), 318214734Srpaulo dev_password_bin, WPS_OOB_DEVICE_PASSWORD_LEN); 319214734Srpaulo 320214734Srpaulo return 0; 321214734Srpaulo} 322214734Srpaulo#endif /* CONFIG_WPS_OOB */ 323