1 /* 2 * Wi-Fi Protected Setup 3 * Copyright (c) 2007-2008, Jouni Malinen <j@w1.fi> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 * 9 * Alternatively, this software may be distributed under the terms of BSD 10 * license. 11 * 12 * See README and COPYING for more details. 13 */ 14 15 #include "includes.h" 16 17 #include "common.h" 18 #include "wps_i.h" 19 #include "wps_dev_attr.h" 20 #include "ieee802_11_defs.h" 21 22 23 /** 24 * wps_init - Initialize WPS Registration protocol data 25 * @cfg: WPS configuration 26 * Returns: Pointer to allocated data or %NULL on failure 27 * 28 * This function is used to initialize WPS data for a registration protocol 29 * instance (i.e., each run of registration protocol as a Registrar of 30 * Enrollee. The caller is responsible for freeing this data after the 31 * registration run has been completed by calling wps_deinit(). 32 */ 33 struct wps_data * wps_init(const struct wps_config *cfg) 34 { 35 struct wps_data *data = os_zalloc(sizeof(*data)); 36 if (data == NULL) 37 return NULL; 38 data->wps = cfg->wps; 39 data->registrar = cfg->registrar; 40 if (cfg->registrar) { 41 os_memcpy(data->uuid_r, cfg->wps->uuid, WPS_UUID_LEN); 42 } else { 43 os_memcpy(data->mac_addr_e, cfg->wps->dev.mac_addr, ETH_ALEN); 44 os_memcpy(data->uuid_e, cfg->wps->uuid, WPS_UUID_LEN); 45 } 46 if (cfg->pin) { 47 data->dev_pw_id = DEV_PW_DEFAULT; 48 data->dev_password = os_malloc(cfg->pin_len); 49 if (data->dev_password == NULL) { 50 os_free(data); 51 return NULL; 52 } 53 os_memcpy(data->dev_password, cfg->pin, cfg->pin_len); 54 data->dev_password_len = cfg->pin_len; 55 } 56 57 data->pbc = cfg->pbc; 58 if (cfg->pbc) { 59 /* Use special PIN '00000000' for PBC */ 60 data->dev_pw_id = DEV_PW_PUSHBUTTON; 61 os_free(data->dev_password); 62 data->dev_password = os_malloc(8); 63 if (data->dev_password == NULL) { 64 os_free(data); 65 return NULL; 66 } 67 os_memset(data->dev_password, '0', 8); 68 data->dev_password_len = 8; 69 } 70 71 data->state = data->registrar ? RECV_M1 : SEND_M1; 72 73 if (cfg->assoc_wps_ie) { 74 struct wps_parse_attr attr; 75 wpa_hexdump_buf(MSG_DEBUG, "WPS: WPS IE from (Re)AssocReq", 76 cfg->assoc_wps_ie); 77 if (wps_parse_msg(cfg->assoc_wps_ie, &attr) < 0) { 78 wpa_printf(MSG_DEBUG, "WPS: Failed to parse WPS IE " 79 "from (Re)AssocReq"); 80 } else if (attr.request_type == NULL) { 81 wpa_printf(MSG_DEBUG, "WPS: No Request Type attribute " 82 "in (Re)AssocReq WPS IE"); 83 } else { 84 wpa_printf(MSG_DEBUG, "WPS: Request Type (from WPS IE " 85 "in (Re)AssocReq WPS IE): %d", 86 *attr.request_type); 87 data->request_type = *attr.request_type; 88 } 89 } 90 91 return data; 92 } 93 94 95 /** 96 * wps_deinit - Deinitialize WPS Registration protocol data 97 * @data: WPS Registration protocol data from wps_init() 98 */ 99 void wps_deinit(struct wps_data *data) 100 { 101 if (data->wps_pin_revealed) { 102 wpa_printf(MSG_DEBUG, "WPS: Full PIN information revealed and " 103 "negotiation failed"); 104 if (data->registrar) 105 wps_registrar_invalidate_pin(data->wps->registrar, 106 data->uuid_e); 107 } else if (data->registrar) 108 wps_registrar_unlock_pin(data->wps->registrar, data->uuid_e); 109 110 wpabuf_free(data->dh_privkey); 111 wpabuf_free(data->dh_pubkey_e); 112 wpabuf_free(data->dh_pubkey_r); 113 wpabuf_free(data->last_msg); 114 os_free(data->dev_password); 115 os_free(data->new_psk); 116 wps_device_data_free(&data->peer_dev); 117 os_free(data); 118 } 119 120 121 /** 122 * wps_process_msg - Process a WPS message 123 * @wps: WPS Registration protocol data from wps_init() 124 * @op_code: Message OP Code 125 * @msg: Message data 126 * Returns: Processing result 127 * 128 * This function is used to process WPS messages with OP Codes WSC_ACK, 129 * WSC_NACK, WSC_MSG, and WSC_Done. The caller (e.g., EAP server/peer) is 130 * responsible for reassembling the messages before calling this function. 131 * Response to this message is built by calling wps_get_msg(). 132 */ 133 enum wps_process_res wps_process_msg(struct wps_data *wps, 134 enum wsc_op_code op_code, 135 const struct wpabuf *msg) 136 { 137 if (wps->registrar) 138 return wps_registrar_process_msg(wps, op_code, msg); 139 else 140 return wps_enrollee_process_msg(wps, op_code, msg); 141 } 142 143 144 /** 145 * wps_get_msg - Build a WPS message 146 * @wps: WPS Registration protocol data from wps_init() 147 * @op_code: Buffer for returning message OP Code 148 * Returns: The generated WPS message or %NULL on failure 149 * 150 * This function is used to build a response to a message processed by calling 151 * wps_process_msg(). The caller is responsible for freeing the buffer. 152 */ 153 struct wpabuf * wps_get_msg(struct wps_data *wps, enum wsc_op_code *op_code) 154 { 155 if (wps->registrar) 156 return wps_registrar_get_msg(wps, op_code); 157 else 158 return wps_enrollee_get_msg(wps, op_code); 159 } 160 161 162 /** 163 * wps_is_selected_pbc_registrar - Check whether WPS IE indicates active PBC 164 * @msg: WPS IE contents from Beacon or Probe Response frame 165 * Returns: 1 if PBC Registrar is active, 0 if not 166 */ 167 int wps_is_selected_pbc_registrar(const struct wpabuf *msg) 168 { 169 struct wps_parse_attr attr; 170 171 /* 172 * In theory, this could also verify that attr.sel_reg_config_methods 173 * includes WPS_CONFIG_PUSHBUTTON, but some deployed AP implementations 174 * do not set Selected Registrar Config Methods attribute properly, so 175 * it is safer to just use Device Password ID here. 176 */ 177 178 if (wps_parse_msg(msg, &attr) < 0 || 179 !attr.selected_registrar || *attr.selected_registrar == 0 || 180 !attr.dev_password_id || 181 WPA_GET_BE16(attr.dev_password_id) != DEV_PW_PUSHBUTTON) 182 return 0; 183 184 return 1; 185 } 186 187 188 /** 189 * wps_is_selected_pin_registrar - Check whether WPS IE indicates active PIN 190 * @msg: WPS IE contents from Beacon or Probe Response frame 191 * Returns: 1 if PIN Registrar is active, 0 if not 192 */ 193 int wps_is_selected_pin_registrar(const struct wpabuf *msg) 194 { 195 struct wps_parse_attr attr; 196 197 /* 198 * In theory, this could also verify that attr.sel_reg_config_methods 199 * includes WPS_CONFIG_LABEL, WPS_CONFIG_DISPLAY, or WPS_CONFIG_KEYPAD, 200 * but some deployed AP implementations do not set Selected Registrar 201 * Config Methods attribute properly, so it is safer to just use 202 * Device Password ID here. 203 */ 204 205 if (wps_parse_msg(msg, &attr) < 0) 206 return 0; 207 208 if (!attr.selected_registrar || *attr.selected_registrar == 0) 209 return 0; 210 211 if (attr.dev_password_id != NULL && 212 WPA_GET_BE16(attr.dev_password_id) == DEV_PW_PUSHBUTTON) 213 return 0; 214 215 return 1; 216 } 217 218 219 /** 220 * wps_get_uuid_e - Get UUID-E from WPS IE 221 * @msg: WPS IE contents from Beacon or Probe Response frame 222 * Returns: Pointer to UUID-E or %NULL if not included 223 * 224 * The returned pointer is to the msg contents and it remains valid only as 225 * long as the msg buffer is valid. 226 */ 227 const u8 * wps_get_uuid_e(const struct wpabuf *msg) 228 { 229 struct wps_parse_attr attr; 230 231 if (wps_parse_msg(msg, &attr) < 0) 232 return NULL; 233 return attr.uuid_e; 234 } 235 236 237 /** 238 * wps_build_assoc_req_ie - Build WPS IE for (Re)Association Request 239 * @req_type: Value for Request Type attribute 240 * Returns: WPS IE or %NULL on failure 241 * 242 * The caller is responsible for freeing the buffer. 243 */ 244 struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type) 245 { 246 struct wpabuf *ie; 247 u8 *len; 248 249 wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for (Re)Association " 250 "Request"); 251 ie = wpabuf_alloc(100); 252 if (ie == NULL) 253 return NULL; 254 255 wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC); 256 len = wpabuf_put(ie, 1); 257 wpabuf_put_be32(ie, WPS_DEV_OUI_WFA); 258 259 if (wps_build_version(ie) || 260 wps_build_req_type(ie, req_type)) { 261 wpabuf_free(ie); 262 return NULL; 263 } 264 265 *len = wpabuf_len(ie) - 2; 266 267 return ie; 268 } 269 270 271 /** 272 * wps_build_probe_req_ie - Build WPS IE for Probe Request 273 * @pbc: Whether searching for PBC mode APs 274 * @dev: Device attributes 275 * @uuid: Own UUID 276 * @req_type: Value for Request Type attribute 277 * Returns: WPS IE or %NULL on failure 278 * 279 * The caller is responsible for freeing the buffer. 280 */ 281 struct wpabuf * wps_build_probe_req_ie(int pbc, struct wps_device_data *dev, 282 const u8 *uuid, 283 enum wps_request_type req_type) 284 { 285 struct wpabuf *ie; 286 u8 *len; 287 u16 methods; 288 289 wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for Probe Request"); 290 291 ie = wpabuf_alloc(200); 292 if (ie == NULL) 293 return NULL; 294 295 wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC); 296 len = wpabuf_put(ie, 1); 297 wpabuf_put_be32(ie, WPS_DEV_OUI_WFA); 298 299 if (pbc) 300 methods = WPS_CONFIG_PUSHBUTTON; 301 else 302 methods = WPS_CONFIG_LABEL | WPS_CONFIG_DISPLAY | 303 WPS_CONFIG_KEYPAD; 304 305 if (wps_build_version(ie) || 306 wps_build_req_type(ie, req_type) || 307 wps_build_config_methods(ie, methods) || 308 wps_build_uuid_e(ie, uuid) || 309 wps_build_primary_dev_type(dev, ie) || 310 wps_build_rf_bands(dev, ie) || 311 wps_build_assoc_state(NULL, ie) || 312 wps_build_config_error(ie, WPS_CFG_NO_ERROR) || 313 wps_build_dev_password_id(ie, pbc ? DEV_PW_PUSHBUTTON : 314 DEV_PW_DEFAULT)) { 315 wpabuf_free(ie); 316 return NULL; 317 } 318 319 *len = wpabuf_len(ie) - 2; 320 321 return ie; 322 } 323 324 325 void wps_free_pending_msgs(struct upnp_pending_message *msgs) 326 { 327 struct upnp_pending_message *p, *prev; 328 p = msgs; 329 while (p) { 330 prev = p; 331 p = p->next; 332 wpabuf_free(prev->msg); 333 os_free(prev); 334 } 335 } 336