139beb93cSSam Leffler /*
239beb93cSSam Leffler  * EAP peer method: Test method for vendor specific (expanded) EAP type
35b9c547cSRui Paulo  * Copyright (c) 2005-2015, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo  * See README for more details.
739beb93cSSam Leffler  *
839beb93cSSam Leffler  * This file implements a vendor specific test method using EAP expanded types.
939beb93cSSam Leffler  * This is only for test use and must not be used for authentication since no
1039beb93cSSam Leffler  * security is provided.
1139beb93cSSam Leffler  */
1239beb93cSSam Leffler 
1339beb93cSSam Leffler #include "includes.h"
1439beb93cSSam Leffler 
1539beb93cSSam Leffler #include "common.h"
1639beb93cSSam Leffler #include "eap_i.h"
1739beb93cSSam Leffler #include "eloop.h"
1839beb93cSSam Leffler 
1939beb93cSSam Leffler 
20f05cddf9SRui Paulo #define EAP_VENDOR_ID EAP_VENDOR_HOSTAP
2139beb93cSSam Leffler #define EAP_VENDOR_TYPE 0xfcfbfaf9
2239beb93cSSam Leffler 
2339beb93cSSam Leffler 
2439beb93cSSam Leffler struct eap_vendor_test_data {
2539beb93cSSam Leffler 	enum { INIT, CONFIRM, SUCCESS } state;
2639beb93cSSam Leffler 	int first_try;
275b9c547cSRui Paulo 	int test_pending_req;
2839beb93cSSam Leffler };
2939beb93cSSam Leffler 
3039beb93cSSam Leffler 
eap_vendor_test_init(struct eap_sm * sm)3139beb93cSSam Leffler static void * eap_vendor_test_init(struct eap_sm *sm)
3239beb93cSSam Leffler {
3339beb93cSSam Leffler 	struct eap_vendor_test_data *data;
345b9c547cSRui Paulo 	const u8 *password;
355b9c547cSRui Paulo 	size_t password_len;
365b9c547cSRui Paulo 
3739beb93cSSam Leffler 	data = os_zalloc(sizeof(*data));
3839beb93cSSam Leffler 	if (data == NULL)
3939beb93cSSam Leffler 		return NULL;
4039beb93cSSam Leffler 	data->state = INIT;
4139beb93cSSam Leffler 	data->first_try = 1;
425b9c547cSRui Paulo 
435b9c547cSRui Paulo 	password = eap_get_config_password(sm, &password_len);
445b9c547cSRui Paulo 	data->test_pending_req = password && password_len == 7 &&
455b9c547cSRui Paulo 		os_memcmp(password, "pending", 7) == 0;
465b9c547cSRui Paulo 
4739beb93cSSam Leffler 	return data;
4839beb93cSSam Leffler }
4939beb93cSSam Leffler 
5039beb93cSSam Leffler 
eap_vendor_test_deinit(struct eap_sm * sm,void * priv)5139beb93cSSam Leffler static void eap_vendor_test_deinit(struct eap_sm *sm, void *priv)
5239beb93cSSam Leffler {
5339beb93cSSam Leffler 	struct eap_vendor_test_data *data = priv;
5439beb93cSSam Leffler 	os_free(data);
5539beb93cSSam Leffler }
5639beb93cSSam Leffler 
5739beb93cSSam Leffler 
eap_vendor_ready(void * eloop_ctx,void * timeout_ctx)5839beb93cSSam Leffler static void eap_vendor_ready(void *eloop_ctx, void *timeout_ctx)
5939beb93cSSam Leffler {
6039beb93cSSam Leffler 	struct eap_sm *sm = eloop_ctx;
6139beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Ready to re-process pending "
6239beb93cSSam Leffler 		   "request");
6339beb93cSSam Leffler 	eap_notify_pending(sm);
6439beb93cSSam Leffler }
6539beb93cSSam Leffler 
6639beb93cSSam Leffler 
eap_vendor_test_process(struct eap_sm * sm,void * priv,struct eap_method_ret * ret,const struct wpabuf * reqData)6739beb93cSSam Leffler static struct wpabuf * eap_vendor_test_process(struct eap_sm *sm, void *priv,
6839beb93cSSam Leffler 					       struct eap_method_ret *ret,
6939beb93cSSam Leffler 					       const struct wpabuf *reqData)
7039beb93cSSam Leffler {
7139beb93cSSam Leffler 	struct eap_vendor_test_data *data = priv;
7239beb93cSSam Leffler 	struct wpabuf *resp;
7339beb93cSSam Leffler 	const u8 *pos;
7439beb93cSSam Leffler 	size_t len;
7539beb93cSSam Leffler 
7639beb93cSSam Leffler 	pos = eap_hdr_validate(EAP_VENDOR_ID, EAP_VENDOR_TYPE, reqData, &len);
7739beb93cSSam Leffler 	if (pos == NULL || len < 1) {
78*c1d255d3SCy Schubert 		ret->ignore = true;
7939beb93cSSam Leffler 		return NULL;
8039beb93cSSam Leffler 	}
8139beb93cSSam Leffler 
8239beb93cSSam Leffler 	if (data->state == INIT && *pos != 1) {
8339beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Unexpected message "
8439beb93cSSam Leffler 			   "%d in INIT state", *pos);
85*c1d255d3SCy Schubert 		ret->ignore = true;
8639beb93cSSam Leffler 		return NULL;
8739beb93cSSam Leffler 	}
8839beb93cSSam Leffler 
8939beb93cSSam Leffler 	if (data->state == CONFIRM && *pos != 3) {
9039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Unexpected message "
9139beb93cSSam Leffler 			   "%d in CONFIRM state", *pos);
92*c1d255d3SCy Schubert 		ret->ignore = true;
9339beb93cSSam Leffler 		return NULL;
9439beb93cSSam Leffler 	}
9539beb93cSSam Leffler 
9639beb93cSSam Leffler 	if (data->state == SUCCESS) {
9739beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Unexpected message "
9839beb93cSSam Leffler 			   "in SUCCESS state");
99*c1d255d3SCy Schubert 		ret->ignore = true;
10039beb93cSSam Leffler 		return NULL;
10139beb93cSSam Leffler 	}
10239beb93cSSam Leffler 
10339beb93cSSam Leffler 	if (data->state == CONFIRM) {
1045b9c547cSRui Paulo 		if (data->test_pending_req && data->first_try) {
10539beb93cSSam Leffler 			data->first_try = 0;
10639beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Testing "
10739beb93cSSam Leffler 				   "pending request");
108*c1d255d3SCy Schubert 			ret->ignore = true;
10939beb93cSSam Leffler 			eloop_register_timeout(1, 0, eap_vendor_ready, sm,
11039beb93cSSam Leffler 					       NULL);
11139beb93cSSam Leffler 			return NULL;
11239beb93cSSam Leffler 		}
11339beb93cSSam Leffler 	}
11439beb93cSSam Leffler 
115*c1d255d3SCy Schubert 	ret->ignore = false;
11639beb93cSSam Leffler 
11739beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Generating Response");
118*c1d255d3SCy Schubert 	ret->allowNotifications = true;
11939beb93cSSam Leffler 
12039beb93cSSam Leffler 	resp = eap_msg_alloc(EAP_VENDOR_ID, EAP_VENDOR_TYPE, 1,
12139beb93cSSam Leffler 			     EAP_CODE_RESPONSE, eap_get_id(reqData));
12239beb93cSSam Leffler 	if (resp == NULL)
12339beb93cSSam Leffler 		return NULL;
12439beb93cSSam Leffler 
12539beb93cSSam Leffler 	if (data->state == INIT) {
12639beb93cSSam Leffler 		wpabuf_put_u8(resp, 2);
12739beb93cSSam Leffler 		data->state = CONFIRM;
12839beb93cSSam Leffler 		ret->methodState = METHOD_CONT;
12939beb93cSSam Leffler 		ret->decision = DECISION_FAIL;
13039beb93cSSam Leffler 	} else {
13139beb93cSSam Leffler 		wpabuf_put_u8(resp, 4);
13239beb93cSSam Leffler 		data->state = SUCCESS;
13339beb93cSSam Leffler 		ret->methodState = METHOD_DONE;
13439beb93cSSam Leffler 		ret->decision = DECISION_UNCOND_SUCC;
13539beb93cSSam Leffler 	}
13639beb93cSSam Leffler 
13739beb93cSSam Leffler 	return resp;
13839beb93cSSam Leffler }
13939beb93cSSam Leffler 
14039beb93cSSam Leffler 
eap_vendor_test_isKeyAvailable(struct eap_sm * sm,void * priv)141*c1d255d3SCy Schubert static bool eap_vendor_test_isKeyAvailable(struct eap_sm *sm, void *priv)
14239beb93cSSam Leffler {
14339beb93cSSam Leffler 	struct eap_vendor_test_data *data = priv;
14439beb93cSSam Leffler 	return data->state == SUCCESS;
14539beb93cSSam Leffler }
14639beb93cSSam Leffler 
14739beb93cSSam Leffler 
eap_vendor_test_getKey(struct eap_sm * sm,void * priv,size_t * len)14839beb93cSSam Leffler static u8 * eap_vendor_test_getKey(struct eap_sm *sm, void *priv, size_t *len)
14939beb93cSSam Leffler {
15039beb93cSSam Leffler 	struct eap_vendor_test_data *data = priv;
15139beb93cSSam Leffler 	u8 *key;
15239beb93cSSam Leffler 	const int key_len = 64;
15339beb93cSSam Leffler 
15439beb93cSSam Leffler 	if (data->state != SUCCESS)
15539beb93cSSam Leffler 		return NULL;
15639beb93cSSam Leffler 
15739beb93cSSam Leffler 	key = os_malloc(key_len);
15839beb93cSSam Leffler 	if (key == NULL)
15939beb93cSSam Leffler 		return NULL;
16039beb93cSSam Leffler 
16139beb93cSSam Leffler 	os_memset(key, 0x11, key_len / 2);
16239beb93cSSam Leffler 	os_memset(key + key_len / 2, 0x22, key_len / 2);
16339beb93cSSam Leffler 	*len = key_len;
16439beb93cSSam Leffler 
16539beb93cSSam Leffler 	return key;
16639beb93cSSam Leffler }
16739beb93cSSam Leffler 
16839beb93cSSam Leffler 
eap_peer_vendor_test_register(void)16939beb93cSSam Leffler int eap_peer_vendor_test_register(void)
17039beb93cSSam Leffler {
17139beb93cSSam Leffler 	struct eap_method *eap;
17239beb93cSSam Leffler 
17339beb93cSSam Leffler 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
17439beb93cSSam Leffler 				    EAP_VENDOR_ID, EAP_VENDOR_TYPE,
17539beb93cSSam Leffler 				    "VENDOR-TEST");
17639beb93cSSam Leffler 	if (eap == NULL)
17739beb93cSSam Leffler 		return -1;
17839beb93cSSam Leffler 
17939beb93cSSam Leffler 	eap->init = eap_vendor_test_init;
18039beb93cSSam Leffler 	eap->deinit = eap_vendor_test_deinit;
18139beb93cSSam Leffler 	eap->process = eap_vendor_test_process;
18239beb93cSSam Leffler 	eap->isKeyAvailable = eap_vendor_test_isKeyAvailable;
18339beb93cSSam Leffler 	eap->getKey = eap_vendor_test_getKey;
18439beb93cSSam Leffler 
185780fb4a2SCy Schubert 	return eap_peer_method_register(eap);
18639beb93cSSam Leffler }
187