1 /* 2 * Wi-Fi Protected Setup - attribute building 3 * Copyright (c) 2008, Jouni Malinen <j (at) w1.fi> 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9 #include "includes.h" 10 11 #include "common.h" 12 #include "crypto/aes_wrap.h" 13 #include "crypto/crypto.h" 14 #include "crypto/dh_group5.h" 15 #include "crypto/sha256.h" 16 #include "crypto/random.h" 17 #include "common/ieee802_11_defs.h" 18 #include "wps_i.h" 19 20 21 int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg) 22 { 23 struct wpabuf *pubkey; 24 25 wpa_printf(MSG_DEBUG, "WPS: * Public Key"); 26 wpabuf_free(wps->dh_privkey); 27 wps->dh_privkey = NULL; 28 if (wps->dev_pw_id != DEV_PW_DEFAULT && wps->wps->dh_privkey && 29 wps->wps->dh_ctx) { 30 wpa_printf(MSG_DEBUG, "WPS: Using pre-configured DH keys"); 31 if (wps->wps->dh_pubkey == NULL) { 32 wpa_printf(MSG_DEBUG, 33 "WPS: wps->wps->dh_pubkey == NULL"); 34 return -1; 35 } 36 wps->dh_privkey = wpabuf_dup(wps->wps->dh_privkey); 37 wps->dh_ctx = wps->wps->dh_ctx; 38 wps->wps->dh_ctx = NULL; 39 pubkey = wpabuf_dup(wps->wps->dh_pubkey); 40 #ifdef CONFIG_WPS_NFC 41 } else if (wps->dev_pw_id >= 0x10 && wps->wps->ap && 42 wps->dev_pw_id == wps->wps->ap_nfc_dev_pw_id) { 43 wpa_printf(MSG_DEBUG, "WPS: Using NFC password token DH keys"); 44 if (wps->wps->ap_nfc_dh_privkey == NULL) { 45 wpa_printf(MSG_DEBUG, 46 "WPS: wps->wps->ap_nfc_dh_privkey == NULL"); 47 return -1; 48 } 49 if (wps->wps->ap_nfc_dh_pubkey == NULL) { 50 wpa_printf(MSG_DEBUG, 51 "WPS: wps->wps->ap_nfc_dh_pubkey == NULL"); 52 return -1; 53 } 54 wps->dh_privkey = wpabuf_dup(wps->wps->ap_nfc_dh_privkey); 55 pubkey = wpabuf_dup(wps->wps->ap_nfc_dh_pubkey); 56 wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, pubkey); 57 #endif /* CONFIG_WPS_NFC */ 58 } else { 59 wpa_printf(MSG_DEBUG, "WPS: Generate new DH keys"); 60 dh5_free(wps->dh_ctx); 61 wps->dh_ctx = dh5_init(&wps->dh_privkey, &pubkey); 62 pubkey = wpabuf_zeropad(pubkey, 192); 63 } 64 if (wps->dh_ctx == NULL || wps->dh_privkey == NULL || pubkey == NULL) { 65 wpa_printf(MSG_DEBUG, "WPS: Failed to initialize " 66 "Diffie-Hellman handshake"); 67 wpabuf_free(pubkey); 68 return -1; 69 } 70 wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH Private Key", wps->dh_privkey); 71 wpa_hexdump_buf(MSG_DEBUG, "WPS: DH own Public Key", pubkey); 72 73 wpabuf_put_be16(msg, ATTR_PUBLIC_KEY); 74 wpabuf_put_be16(msg, wpabuf_len(pubkey)); 75 wpabuf_put_buf(msg, pubkey); 76 77 if (wps->registrar) { 78 wpabuf_free(wps->dh_pubkey_r); 79 wps->dh_pubkey_r = pubkey; 80 } else { 81 wpabuf_free(wps->dh_pubkey_e); 82 wps->dh_pubkey_e = pubkey; 83 } 84 85 return 0; 86 } 87 88 89 int wps_build_req_type(struct wpabuf *msg, enum wps_request_type type) 90 { 91 wpa_printf(MSG_DEBUG, "WPS: * Request Type"); 92 wpabuf_put_be16(msg, ATTR_REQUEST_TYPE); 93 wpabuf_put_be16(msg, 1); 94 wpabuf_put_u8(msg, type); 95 return 0; 96 } 97 98 99 int wps_build_resp_type(struct wpabuf *msg, enum wps_response_type type) 100 { 101 wpa_printf(MSG_DEBUG, "WPS: * Response Type (%d)", type); 102 wpabuf_put_be16(msg, ATTR_RESPONSE_TYPE); 103 wpabuf_put_be16(msg, 1); 104 wpabuf_put_u8(msg, type); 105 return 0; 106 } 107 108 109 int wps_build_config_methods(struct wpabuf *msg, u16 methods) 110 { 111 wpa_printf(MSG_DEBUG, "WPS: * Config Methods (%x)", methods); 112 wpabuf_put_be16(msg, ATTR_CONFIG_METHODS); 113 wpabuf_put_be16(msg, 2); 114 wpabuf_put_be16(msg, methods); 115 return 0; 116 } 117 118 119 int wps_build_uuid_e(struct wpabuf *msg, const u8 *uuid) 120 { 121 wpa_printf(MSG_DEBUG, "WPS: * UUID-E"); 122 wpabuf_put_be16(msg, ATTR_UUID_E); 123 wpabuf_put_be16(msg, WPS_UUID_LEN); 124 wpabuf_put_data(msg, uuid, WPS_UUID_LEN); 125 return 0; 126 } 127 128 129 int wps_build_dev_password_id(struct wpabuf *msg, u16 id) 130 { 131 wpa_printf(MSG_DEBUG, "WPS: * Device Password ID (%d)", id); 132 wpabuf_put_be16(msg, ATTR_DEV_PASSWORD_ID); 133 wpabuf_put_be16(msg, 2); 134 wpabuf_put_be16(msg, id); 135 return 0; 136 } 137 138 139 int wps_build_config_error(struct wpabuf *msg, u16 err) 140 { 141 wpa_printf(MSG_DEBUG, "WPS: * Configuration Error (%d)", err); 142 wpabuf_put_be16(msg, ATTR_CONFIG_ERROR); 143 wpabuf_put_be16(msg, 2); 144 wpabuf_put_be16(msg, err); 145 return 0; 146 } 147 148 149 int wps_build_authenticator(struct wps_data *wps, struct wpabuf *msg) 150 { 151 u8 hash[SHA256_MAC_LEN]; 152 const u8 *addr[2]; 153 size_t len[2]; 154 155 if (wps->last_msg == NULL) { 156 wpa_printf(MSG_DEBUG, "WPS: Last message not available for " 157 "building authenticator"); 158 return -1; 159 } 160 161 /* Authenticator = HMAC-SHA256_AuthKey(M_prev || M_curr*) 162 * (M_curr* is M_curr without the Authenticator attribute) 163 */ 164 addr[0] = wpabuf_head(wps->last_msg); 165 len[0] = wpabuf_len(wps->last_msg); 166 addr[1] = wpabuf_head(msg); 167 len[1] = wpabuf_len(msg); 168 hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash); 169 170 wpa_printf(MSG_DEBUG, "WPS: * Authenticator"); 171 wpabuf_put_be16(msg, ATTR_AUTHENTICATOR); 172 wpabuf_put_be16(msg, WPS_AUTHENTICATOR_LEN); 173 wpabuf_put_data(msg, hash, WPS_AUTHENTICATOR_LEN); 174 175 return 0; 176 } 177 178 179 int wps_build_version(struct wpabuf *msg) 180 { 181 /* 182 * Note: This attribute is deprecated and set to hardcoded 0x10 for 183 * backwards compatibility reasons. The real version negotiation is 184 * done with Version2. 185 */ 186 wpa_printf(MSG_DEBUG, "WPS: * Version (hardcoded 0x10)"); 187 wpabuf_put_be16(msg, ATTR_VERSION); 188 wpabuf_put_be16(msg, 1); 189 wpabuf_put_u8(msg, 0x10); 190 return 0; 191 } 192 193 194 int wps_build_wfa_ext(struct wpabuf *msg, int req_to_enroll, 195 const u8 *auth_macs, size_t auth_macs_count) 196 { 197 #ifdef CONFIG_WPS2 198 u8 *len; 199 200 wpabuf_put_be16(msg, ATTR_VENDOR_EXT); 201 len = wpabuf_put(msg, 2); /* to be filled */ 202 wpabuf_put_be24(msg, WPS_VENDOR_ID_WFA); 203 204 wpa_printf(MSG_DEBUG, "WPS: * Version2 (0x%x)", WPS_VERSION); 205 wpabuf_put_u8(msg, WFA_ELEM_VERSION2); 206 wpabuf_put_u8(msg, 1); 207 wpabuf_put_u8(msg, WPS_VERSION); 208 209 if (req_to_enroll) { 210 wpa_printf(MSG_DEBUG, "WPS: * Request to Enroll (1)"); 211 wpabuf_put_u8(msg, WFA_ELEM_REQUEST_TO_ENROLL); 212 wpabuf_put_u8(msg, 1); 213 wpabuf_put_u8(msg, 1); 214 } 215 216 if (auth_macs && auth_macs_count) { 217 size_t i; 218 wpa_printf(MSG_DEBUG, "WPS: * AuthorizedMACs (count=%d)", 219 (int) auth_macs_count); 220 wpabuf_put_u8(msg, WFA_ELEM_AUTHORIZEDMACS); 221 wpabuf_put_u8(msg, auth_macs_count * ETH_ALEN); 222 wpabuf_put_data(msg, auth_macs, auth_macs_count * ETH_ALEN); 223 for (i = 0; i < auth_macs_count; i++) 224 wpa_printf(MSG_DEBUG, "WPS: AuthorizedMAC: " MACSTR, 225 MAC2STR(&auth_macs[i * ETH_ALEN])); 226 } 227 228 WPA_PUT_BE16(len, (u8 *) wpabuf_put(msg, 0) - len - 2); 229 #endif /* CONFIG_WPS2 */ 230 231 #ifdef CONFIG_WPS_TESTING 232 if (WPS_VERSION > 0x20) { 233 wpa_printf(MSG_DEBUG, "WPS: * Extensibility Testing - extra " 234 "attribute"); 235 wpabuf_put_be16(msg, ATTR_EXTENSIBILITY_TEST); 236 wpabuf_put_be16(msg, 1); 237 wpabuf_put_u8(msg, 42); 238 } 239 #endif /* CONFIG_WPS_TESTING */ 240 return 0; 241 } 242 243 244 int wps_build_msg_type(struct wpabuf *msg, enum wps_msg_type msg_type) 245 { 246 wpa_printf(MSG_DEBUG, "WPS: * Message Type (%d)", msg_type); 247 wpabuf_put_be16(msg, ATTR_MSG_TYPE); 248 wpabuf_put_be16(msg, 1); 249 wpabuf_put_u8(msg, msg_type); 250 return 0; 251 } 252 253 254 int wps_build_enrollee_nonce(struct wps_data *wps, struct wpabuf *msg) 255 { 256 wpa_printf(MSG_DEBUG, "WPS: * Enrollee Nonce"); 257 wpabuf_put_be16(msg, ATTR_ENROLLEE_NONCE); 258 wpabuf_put_be16(msg, WPS_NONCE_LEN); 259 wpabuf_put_data(msg, wps->nonce_e, WPS_NONCE_LEN); 260 return 0; 261 } 262 263 264 int wps_build_registrar_nonce(struct wps_data *wps, struct wpabuf *msg) 265 { 266 wpa_printf(MSG_DEBUG, "WPS: * Registrar Nonce"); 267 wpabuf_put_be16(msg, ATTR_REGISTRAR_NONCE); 268 wpabuf_put_be16(msg, WPS_NONCE_LEN); 269 wpabuf_put_data(msg, wps->nonce_r, WPS_NONCE_LEN); 270 return 0; 271 } 272 273 274 int wps_build_auth_type_flags(struct wps_data *wps, struct wpabuf *msg) 275 { 276 u16 auth_types = WPS_AUTH_TYPES; 277 #ifdef CONFIG_WPS2 278 auth_types &= ~WPS_AUTH_SHARED; 279 #endif /* CONFIG_WPS2 */ 280 wpa_printf(MSG_DEBUG, "WPS: * Authentication Type Flags"); 281 wpabuf_put_be16(msg, ATTR_AUTH_TYPE_FLAGS); 282 wpabuf_put_be16(msg, 2); 283 wpabuf_put_be16(msg, auth_types); 284 return 0; 285 } 286 287 288 int wps_build_encr_type_flags(struct wps_data *wps, struct wpabuf *msg) 289 { 290 u16 encr_types = WPS_ENCR_TYPES; 291 #ifdef CONFIG_WPS2 292 encr_types &= ~WPS_ENCR_WEP; 293 #endif /* CONFIG_WPS2 */ 294 wpa_printf(MSG_DEBUG, "WPS: * Encryption Type Flags"); 295 wpabuf_put_be16(msg, ATTR_ENCR_TYPE_FLAGS); 296 wpabuf_put_be16(msg, 2); 297 wpabuf_put_be16(msg, encr_types); 298 return 0; 299 } 300 301 302 int wps_build_conn_type_flags(struct wps_data *wps, struct wpabuf *msg) 303 { 304 wpa_printf(MSG_DEBUG, "WPS: * Connection Type Flags"); 305 wpabuf_put_be16(msg, ATTR_CONN_TYPE_FLAGS); 306 wpabuf_put_be16(msg, 1); 307 wpabuf_put_u8(msg, WPS_CONN_ESS); 308 return 0; 309 } 310 311 312 int wps_build_assoc_state(struct wps_data *wps, struct wpabuf *msg) 313 { 314 wpa_printf(MSG_DEBUG, "WPS: * Association State"); 315 wpabuf_put_be16(msg, ATTR_ASSOC_STATE); 316 wpabuf_put_be16(msg, 2); 317 wpabuf_put_be16(msg, WPS_ASSOC_NOT_ASSOC); 318 return 0; 319 } 320 321 322 int wps_build_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg) 323 { 324 u8 hash[SHA256_MAC_LEN]; 325 326 wpa_printf(MSG_DEBUG, "WPS: * Key Wrap Authenticator"); 327 hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, wpabuf_head(msg), 328 wpabuf_len(msg), hash); 329 330 wpabuf_put_be16(msg, ATTR_KEY_WRAP_AUTH); 331 wpabuf_put_be16(msg, WPS_KWA_LEN); 332 wpabuf_put_data(msg, hash, WPS_KWA_LEN); 333 return 0; 334 } 335 336 337 int wps_build_encr_settings(struct wps_data *wps, struct wpabuf *msg, 338 struct wpabuf *plain) 339 { 340 size_t pad_len; 341 const size_t block_size = 16; 342 u8 *iv, *data; 343 344 wpa_printf(MSG_DEBUG, "WPS: * Encrypted Settings"); 345 346 /* PKCS#5 v2.0 pad */ 347 pad_len = block_size - wpabuf_len(plain) % block_size; 348 os_memset(wpabuf_put(plain, pad_len), pad_len, pad_len); 349 350 wpabuf_put_be16(msg, ATTR_ENCR_SETTINGS); 351 wpabuf_put_be16(msg, block_size + wpabuf_len(plain)); 352 353 iv = wpabuf_put(msg, block_size); 354 if (random_get_bytes(iv, block_size) < 0) 355 return -1; 356 357 data = wpabuf_put(msg, 0); 358 wpabuf_put_buf(msg, plain); 359 if (aes_128_cbc_encrypt(wps->keywrapkey, iv, data, wpabuf_len(plain))) 360 return -1; 361 362 return 0; 363 } 364 365 366 #ifdef CONFIG_WPS_OOB 367 int wps_build_oob_dev_pw(struct wpabuf *msg, u16 dev_pw_id, 368 const struct wpabuf *pubkey, const u8 *dev_pw, 369 size_t dev_pw_len) 370 { 371 size_t hash_len; 372 const u8 *addr[1]; 373 u8 pubkey_hash[WPS_HASH_LEN]; 374 375 addr[0] = wpabuf_head(pubkey); 376 hash_len = wpabuf_len(pubkey); 377 sha256_vector(1, addr, &hash_len, pubkey_hash); 378 379 wpabuf_put_be16(msg, ATTR_OOB_DEVICE_PASSWORD); 380 wpabuf_put_be16(msg, WPS_OOB_PUBKEY_HASH_LEN + 2 + dev_pw_len); 381 wpabuf_put_data(msg, pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN); 382 wpabuf_put_be16(msg, dev_pw_id); 383 wpabuf_put_data(msg, dev_pw, dev_pw_len); 384 385 return 0; 386 } 387 #endif /* CONFIG_WPS_OOB */ 388 389 390 /* Encapsulate WPS IE data with one (or more, if needed) IE headers */ 391 struct wpabuf * wps_ie_encapsulate(struct wpabuf *data) 392 { 393 struct wpabuf *ie; 394 const u8 *pos, *end; 395 396 ie = wpabuf_alloc(wpabuf_len(data) + 100); 397 if (ie == NULL) { 398 wpabuf_free(data); 399 return NULL; 400 } 401 402 pos = wpabuf_head(data); 403 end = pos + wpabuf_len(data); 404 405 while (end > pos) { 406 size_t frag_len = end - pos; 407 if (frag_len > 251) 408 frag_len = 251; 409 wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC); 410 wpabuf_put_u8(ie, 4 + frag_len); 411 wpabuf_put_be32(ie, WPS_DEV_OUI_WFA); 412 wpabuf_put_data(ie, pos, frag_len); 413 pos += frag_len; 414 } 415 416 wpabuf_free(data); 417 418 return ie; 419 } 420 421 422 int wps_build_mac_addr(struct wpabuf *msg, const u8 *addr) 423 { 424 wpa_printf(MSG_DEBUG, "WPS: * MAC Address (" MACSTR ")", 425 MAC2STR(addr)); 426 wpabuf_put_be16(msg, ATTR_MAC_ADDR); 427 wpabuf_put_be16(msg, ETH_ALEN); 428 wpabuf_put_data(msg, addr, ETH_ALEN); 429 return 0; 430 } 431