Home | History | Annotate | Download | only in eap_server
      1 /*
      2  * EAP-WSC server for Wi-Fi Protected Setup
      3  * Copyright (c) 2007-2008, Jouni Malinen <j (at) 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 "eloop.h"
     19 #include "eap_i.h"
     20 #include "eap_common/eap_wsc_common.h"
     21 #include "p2p/p2p.h"
     22 #include "wps/wps.h"
     23 
     24 
     25 struct eap_wsc_data {
     26 	enum { START, MESG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state;
     27 	int registrar;
     28 	struct wpabuf *in_buf;
     29 	struct wpabuf *out_buf;
     30 	enum wsc_op_code in_op_code, out_op_code;
     31 	size_t out_used;
     32 	size_t fragment_size;
     33 	struct wps_data *wps;
     34 	int ext_reg_timeout;
     35 };
     36 
     37 
     38 #ifndef CONFIG_NO_STDOUT_DEBUG
     39 static const char * eap_wsc_state_txt(int state)
     40 {
     41 	switch (state) {
     42 	case START:
     43 		return "START";
     44 	case MESG:
     45 		return "MESG";
     46 	case FRAG_ACK:
     47 		return "FRAG_ACK";
     48 	case WAIT_FRAG_ACK:
     49 		return "WAIT_FRAG_ACK";
     50 	case DONE:
     51 		return "DONE";
     52 	case FAIL:
     53 		return "FAIL";
     54 	default:
     55 		return "?";
     56 	}
     57 }
     58 #endif /* CONFIG_NO_STDOUT_DEBUG */
     59 
     60 
     61 static void eap_wsc_state(struct eap_wsc_data *data, int state)
     62 {
     63 	wpa_printf(MSG_DEBUG, "EAP-WSC: %s -> %s",
     64 		   eap_wsc_state_txt(data->state),
     65 		   eap_wsc_state_txt(state));
     66 	data->state = state;
     67 }
     68 
     69 
     70 static void eap_wsc_ext_reg_timeout(void *eloop_ctx, void *timeout_ctx)
     71 {
     72 	struct eap_sm *sm = eloop_ctx;
     73 	struct eap_wsc_data *data = timeout_ctx;
     74 
     75 	if (sm->method_pending != METHOD_PENDING_WAIT)
     76 		return;
     77 
     78 	wpa_printf(MSG_DEBUG, "EAP-WSC: Timeout while waiting for an External "
     79 		   "Registrar");
     80 	data->ext_reg_timeout = 1;
     81 	eap_sm_pending_cb(sm);
     82 }
     83 
     84 
     85 static void * eap_wsc_init(struct eap_sm *sm)
     86 {
     87 	struct eap_wsc_data *data;
     88 	int registrar;
     89 	struct wps_config cfg;
     90 
     91 	if (sm->identity && sm->identity_len == WSC_ID_REGISTRAR_LEN &&
     92 	    os_memcmp(sm->identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) ==
     93 	    0)
     94 		registrar = 0; /* Supplicant is Registrar */
     95 	else if (sm->identity && sm->identity_len == WSC_ID_ENROLLEE_LEN &&
     96 		 os_memcmp(sm->identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN)
     97 		 == 0)
     98 		registrar = 1; /* Supplicant is Enrollee */
     99 	else {
    100 		wpa_hexdump_ascii(MSG_INFO, "EAP-WSC: Unexpected identity",
    101 				  sm->identity, sm->identity_len);
    102 		return NULL;
    103 	}
    104 
    105 	data = os_zalloc(sizeof(*data));
    106 	if (data == NULL)
    107 		return NULL;
    108 	data->state = registrar ? START : MESG;
    109 	data->registrar = registrar;
    110 
    111 	os_memset(&cfg, 0, sizeof(cfg));
    112 	cfg.wps = sm->wps;
    113 	cfg.registrar = registrar;
    114 	if (registrar) {
    115 		if (sm->wps == NULL || sm->wps->registrar == NULL) {
    116 			wpa_printf(MSG_INFO, "EAP-WSC: WPS Registrar not "
    117 				   "initialized");
    118 			os_free(data);
    119 			return NULL;
    120 		}
    121 	} else {
    122 		if (sm->user == NULL || sm->user->password == NULL) {
    123 			/*
    124 			 * In theory, this should not really be needed, but
    125 			 * Windows 7 uses Registrar mode to probe AP's WPS
    126 			 * capabilities before trying to use Enrollee and fails
    127 			 * if the AP does not allow that probing to happen..
    128 			 */
    129 			wpa_printf(MSG_DEBUG, "EAP-WSC: No AP PIN (password) "
    130 				   "configured for Enrollee functionality - "
    131 				   "allow for probing capabilities (M1)");
    132 		} else {
    133 			cfg.pin = sm->user->password;
    134 			cfg.pin_len = sm->user->password_len;
    135 		}
    136 	}
    137 	cfg.assoc_wps_ie = sm->assoc_wps_ie;
    138 	cfg.peer_addr = sm->peer_addr;
    139 #ifdef CONFIG_P2P
    140 	if (sm->assoc_p2p_ie) {
    141 		wpa_printf(MSG_DEBUG, "EAP-WSC: Prefer PSK format for P2P "
    142 			   "client");
    143 		cfg.use_psk_key = 1;
    144 		cfg.p2p_dev_addr = p2p_get_go_dev_addr(sm->assoc_p2p_ie);
    145 	}
    146 #endif /* CONFIG_P2P */
    147 	cfg.pbc_in_m1 = sm->pbc_in_m1;
    148 	data->wps = wps_init(&cfg);
    149 	if (data->wps == NULL) {
    150 		os_free(data);
    151 		return NULL;
    152 	}
    153 	data->fragment_size = sm->fragment_size > 0 ? sm->fragment_size :
    154 		WSC_FRAGMENT_SIZE;
    155 
    156 	return data;
    157 }
    158 
    159 
    160 static void eap_wsc_reset(struct eap_sm *sm, void *priv)
    161 {
    162 	struct eap_wsc_data *data = priv;
    163 	eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data);
    164 	wpabuf_free(data->in_buf);
    165 	wpabuf_free(data->out_buf);
    166 	wps_deinit(data->wps);
    167 	os_free(data);
    168 }
    169 
    170 
    171 static struct wpabuf * eap_wsc_build_start(struct eap_sm *sm,
    172 					   struct eap_wsc_data *data, u8 id)
    173 {
    174 	struct wpabuf *req;
    175 
    176 	req = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, 2,
    177 			    EAP_CODE_REQUEST, id);
    178 	if (req == NULL) {
    179 		wpa_printf(MSG_ERROR, "EAP-WSC: Failed to allocate memory for "
    180 			   "request");
    181 		return NULL;
    182 	}
    183 
    184 	wpa_printf(MSG_DEBUG, "EAP-WSC: Send WSC/Start");
    185 	wpabuf_put_u8(req, WSC_Start); /* Op-Code */
    186 	wpabuf_put_u8(req, 0); /* Flags */
    187 
    188 	return req;
    189 }
    190 
    191 
    192 static struct wpabuf * eap_wsc_build_msg(struct eap_wsc_data *data, u8 id)
    193 {
    194 	struct wpabuf *req;
    195 	u8 flags;
    196 	size_t send_len, plen;
    197 
    198 	flags = 0;
    199 	send_len = wpabuf_len(data->out_buf) - data->out_used;
    200 	if (2 + send_len > data->fragment_size) {
    201 		send_len = data->fragment_size - 2;
    202 		flags |= WSC_FLAGS_MF;
    203 		if (data->out_used == 0) {
    204 			flags |= WSC_FLAGS_LF;
    205 			send_len -= 2;
    206 		}
    207 	}
    208 	plen = 2 + send_len;
    209 	if (flags & WSC_FLAGS_LF)
    210 		plen += 2;
    211 	req = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, plen,
    212 			    EAP_CODE_REQUEST, id);
    213 	if (req == NULL) {
    214 		wpa_printf(MSG_ERROR, "EAP-WSC: Failed to allocate memory for "
    215 			   "request");
    216 		return NULL;
    217 	}
    218 
    219 	wpabuf_put_u8(req, data->out_op_code); /* Op-Code */
    220 	wpabuf_put_u8(req, flags); /* Flags */
    221 	if (flags & WSC_FLAGS_LF)
    222 		wpabuf_put_be16(req, wpabuf_len(data->out_buf));
    223 
    224 	wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used,
    225 			send_len);
    226 	data->out_used += send_len;
    227 
    228 	if (data->out_used == wpabuf_len(data->out_buf)) {
    229 		wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes "
    230 			   "(message sent completely)",
    231 			   (unsigned long) send_len);
    232 		wpabuf_free(data->out_buf);
    233 		data->out_buf = NULL;
    234 		data->out_used = 0;
    235 		eap_wsc_state(data, MESG);
    236 	} else {
    237 		wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes "
    238 			   "(%lu more to send)", (unsigned long) send_len,
    239 			   (unsigned long) wpabuf_len(data->out_buf) -
    240 			   data->out_used);
    241 		eap_wsc_state(data, WAIT_FRAG_ACK);
    242 	}
    243 
    244 	return req;
    245 }
    246 
    247 
    248 static struct wpabuf * eap_wsc_buildReq(struct eap_sm *sm, void *priv, u8 id)
    249 {
    250 	struct eap_wsc_data *data = priv;
    251 
    252 	switch (data->state) {
    253 	case START:
    254 		return eap_wsc_build_start(sm, data, id);
    255 	case MESG:
    256 		if (data->out_buf == NULL) {
    257 			data->out_buf = wps_get_msg(data->wps,
    258 						    &data->out_op_code);
    259 			if (data->out_buf == NULL) {
    260 				wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to "
    261 					   "receive message from WPS");
    262 				return NULL;
    263 			}
    264 			data->out_used = 0;
    265 		}
    266 		/* pass through */
    267 	case WAIT_FRAG_ACK:
    268 		return eap_wsc_build_msg(data, id);
    269 	case FRAG_ACK:
    270 		return eap_wsc_build_frag_ack(id, EAP_CODE_REQUEST);
    271 	default:
    272 		wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected state %d in "
    273 			   "buildReq", data->state);
    274 		return NULL;
    275 	}
    276 }
    277 
    278 
    279 static Boolean eap_wsc_check(struct eap_sm *sm, void *priv,
    280 			     struct wpabuf *respData)
    281 {
    282 	const u8 *pos;
    283 	size_t len;
    284 
    285 	pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
    286 			       respData, &len);
    287 	if (pos == NULL || len < 2) {
    288 		wpa_printf(MSG_INFO, "EAP-WSC: Invalid frame");
    289 		return TRUE;
    290 	}
    291 
    292 	return FALSE;
    293 }
    294 
    295 
    296 static int eap_wsc_process_cont(struct eap_wsc_data *data,
    297 				const u8 *buf, size_t len, u8 op_code)
    298 {
    299 	/* Process continuation of a pending message */
    300 	if (op_code != data->in_op_code) {
    301 		wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d in "
    302 			   "fragment (expected %d)",
    303 			   op_code, data->in_op_code);
    304 		eap_wsc_state(data, FAIL);
    305 		return -1;
    306 	}
    307 
    308 	if (len > wpabuf_tailroom(data->in_buf)) {
    309 		wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment overflow");
    310 		eap_wsc_state(data, FAIL);
    311 		return -1;
    312 	}
    313 
    314 	wpabuf_put_data(data->in_buf, buf, len);
    315 	wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes, waiting for %lu "
    316 		   "bytes more", (unsigned long) len,
    317 		   (unsigned long) wpabuf_tailroom(data->in_buf));
    318 
    319 	return 0;
    320 }
    321 
    322 
    323 static int eap_wsc_process_fragment(struct eap_wsc_data *data,
    324 				    u8 flags, u8 op_code, u16 message_length,
    325 				    const u8 *buf, size_t len)
    326 {
    327 	/* Process a fragment that is not the last one of the message */
    328 	if (data->in_buf == NULL && !(flags & WSC_FLAGS_LF)) {
    329 		wpa_printf(MSG_DEBUG, "EAP-WSC: No Message Length "
    330 			   "field in a fragmented packet");
    331 		return -1;
    332 	}
    333 
    334 	if (data->in_buf == NULL) {
    335 		/* First fragment of the message */
    336 		data->in_buf = wpabuf_alloc(message_length);
    337 		if (data->in_buf == NULL) {
    338 			wpa_printf(MSG_DEBUG, "EAP-WSC: No memory for "
    339 				   "message");
    340 			return -1;
    341 		}
    342 		data->in_op_code = op_code;
    343 		wpabuf_put_data(data->in_buf, buf, len);
    344 		wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes in "
    345 			   "first fragment, waiting for %lu bytes more",
    346 			   (unsigned long) len,
    347 			   (unsigned long) wpabuf_tailroom(data->in_buf));
    348 	}
    349 
    350 	return 0;
    351 }
    352 
    353 
    354 static void eap_wsc_process(struct eap_sm *sm, void *priv,
    355 			    struct wpabuf *respData)
    356 {
    357 	struct eap_wsc_data *data = priv;
    358 	const u8 *start, *pos, *end;
    359 	size_t len;
    360 	u8 op_code, flags;
    361 	u16 message_length = 0;
    362 	enum wps_process_res res;
    363 	struct wpabuf tmpbuf;
    364 
    365 	eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data);
    366 	if (data->ext_reg_timeout) {
    367 		eap_wsc_state(data, FAIL);
    368 		return;
    369 	}
    370 
    371 	pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
    372 			       respData, &len);
    373 	if (pos == NULL || len < 2)
    374 		return; /* Should not happen; message already verified */
    375 
    376 	start = pos;
    377 	end = start + len;
    378 
    379 	op_code = *pos++;
    380 	flags = *pos++;
    381 	if (flags & WSC_FLAGS_LF) {
    382 		if (end - pos < 2) {
    383 			wpa_printf(MSG_DEBUG, "EAP-WSC: Message underflow");
    384 			return;
    385 		}
    386 		message_length = WPA_GET_BE16(pos);
    387 		pos += 2;
    388 
    389 		if (message_length < end - pos) {
    390 			wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message "
    391 				   "Length");
    392 			return;
    393 		}
    394 	}
    395 
    396 	wpa_printf(MSG_DEBUG, "EAP-WSC: Received packet: Op-Code %d "
    397 		   "Flags 0x%x Message Length %d",
    398 		   op_code, flags, message_length);
    399 
    400 	if (data->state == WAIT_FRAG_ACK) {
    401 		if (op_code != WSC_FRAG_ACK) {
    402 			wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d "
    403 				   "in WAIT_FRAG_ACK state", op_code);
    404 			eap_wsc_state(data, FAIL);
    405 			return;
    406 		}
    407 		wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment acknowledged");
    408 		eap_wsc_state(data, MESG);
    409 		return;
    410 	}
    411 
    412 	if (op_code != WSC_ACK && op_code != WSC_NACK && op_code != WSC_MSG &&
    413 	    op_code != WSC_Done) {
    414 		wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d",
    415 			   op_code);
    416 		eap_wsc_state(data, FAIL);
    417 		return;
    418 	}
    419 
    420 	if (data->in_buf &&
    421 	    eap_wsc_process_cont(data, pos, end - pos, op_code) < 0) {
    422 		eap_wsc_state(data, FAIL);
    423 		return;
    424 	}
    425 
    426 	if (flags & WSC_FLAGS_MF) {
    427 		if (eap_wsc_process_fragment(data, flags, op_code,
    428 					     message_length, pos, end - pos) <
    429 		    0)
    430 			eap_wsc_state(data, FAIL);
    431 		else
    432 			eap_wsc_state(data, FRAG_ACK);
    433 		return;
    434 	}
    435 
    436 	if (data->in_buf == NULL) {
    437 		/* Wrap unfragmented messages as wpabuf without extra copy */
    438 		wpabuf_set(&tmpbuf, pos, end - pos);
    439 		data->in_buf = &tmpbuf;
    440 	}
    441 
    442 	res = wps_process_msg(data->wps, op_code, data->in_buf);
    443 	switch (res) {
    444 	case WPS_DONE:
    445 		wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing completed "
    446 			   "successfully - report EAP failure");
    447 		eap_wsc_state(data, FAIL);
    448 		break;
    449 	case WPS_CONTINUE:
    450 		eap_wsc_state(data, MESG);
    451 		break;
    452 	case WPS_FAILURE:
    453 		wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing failed");
    454 		eap_wsc_state(data, FAIL);
    455 		break;
    456 	case WPS_PENDING:
    457 		eap_wsc_state(data, MESG);
    458 		sm->method_pending = METHOD_PENDING_WAIT;
    459 		eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data);
    460 		eloop_register_timeout(5, 0, eap_wsc_ext_reg_timeout,
    461 				       sm, data);
    462 		break;
    463 	}
    464 
    465 	if (data->in_buf != &tmpbuf)
    466 		wpabuf_free(data->in_buf);
    467 	data->in_buf = NULL;
    468 }
    469 
    470 
    471 static Boolean eap_wsc_isDone(struct eap_sm *sm, void *priv)
    472 {
    473 	struct eap_wsc_data *data = priv;
    474 	return data->state == FAIL;
    475 }
    476 
    477 
    478 static Boolean eap_wsc_isSuccess(struct eap_sm *sm, void *priv)
    479 {
    480 	/* EAP-WSC will always result in EAP-Failure */
    481 	return FALSE;
    482 }
    483 
    484 
    485 static int eap_wsc_getTimeout(struct eap_sm *sm, void *priv)
    486 {
    487 	/* Recommended retransmit times: retransmit timeout 5 seconds,
    488 	 * per-message timeout 15 seconds, i.e., 3 tries. */
    489 	sm->MaxRetrans = 2; /* total 3 attempts */
    490 	return 5;
    491 }
    492 
    493 
    494 int eap_server_wsc_register(void)
    495 {
    496 	struct eap_method *eap;
    497 	int ret;
    498 
    499 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
    500 				      EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
    501 				      "WSC");
    502 	if (eap == NULL)
    503 		return -1;
    504 
    505 	eap->init = eap_wsc_init;
    506 	eap->reset = eap_wsc_reset;
    507 	eap->buildReq = eap_wsc_buildReq;
    508 	eap->check = eap_wsc_check;
    509 	eap->process = eap_wsc_process;
    510 	eap->isDone = eap_wsc_isDone;
    511 	eap->isSuccess = eap_wsc_isSuccess;
    512 	eap->getTimeout = eap_wsc_getTimeout;
    513 
    514 	ret = eap_server_method_register(eap);
    515 	if (ret)
    516 		eap_server_method_free(eap);
    517 	return ret;
    518 }
    519