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