1 /*
2  * EAP peer method: Test method for vendor specific (expanded) EAP type
3  * Copyright (c) 2005-2015, 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  * This file implements a vendor specific test method using EAP expanded types.
9  * This is only for test use and must not be used for authentication since no
10  * security is provided.
11  */
12 
13 #include "includes.h"
14 
15 #include "common.h"
16 #include "eap_i.h"
17 #include "eloop.h"
18 
19 
20 #define EAP_VENDOR_ID EAP_VENDOR_HOSTAP
21 #define EAP_VENDOR_TYPE 0xfcfbfaf9
22 
23 
24 struct eap_vendor_test_data {
25 	enum { INIT, CONFIRM, SUCCESS } state;
26 	int first_try;
27 	int test_pending_req;
28 };
29 
30 
31 static void * eap_vendor_test_init(struct eap_sm *sm)
32 {
33 	struct eap_vendor_test_data *data;
34 	const u8 *password;
35 	size_t password_len;
36 
37 	data = os_zalloc(sizeof(*data));
38 	if (data == NULL)
39 		return NULL;
40 	data->state = INIT;
41 	data->first_try = 1;
42 
43 	password = eap_get_config_password(sm, &password_len);
44 	data->test_pending_req = password && password_len == 7 &&
45 		os_memcmp(password, "pending", 7) == 0;
46 
47 	return data;
48 }
49 
50 
51 static void eap_vendor_test_deinit(struct eap_sm *sm, void *priv)
52 {
53 	struct eap_vendor_test_data *data = priv;
54 	os_free(data);
55 }
56 
57 
58 static void eap_vendor_ready(void *eloop_ctx, void *timeout_ctx)
59 {
60 	struct eap_sm *sm = eloop_ctx;
61 	wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Ready to re-process pending "
62 		   "request");
63 	eap_notify_pending(sm);
64 }
65 
66 
67 static struct wpabuf * eap_vendor_test_process(struct eap_sm *sm, void *priv,
68 					       struct eap_method_ret *ret,
69 					       const struct wpabuf *reqData)
70 {
71 	struct eap_vendor_test_data *data = priv;
72 	struct wpabuf *resp;
73 	const u8 *pos;
74 	size_t len;
75 
76 	pos = eap_hdr_validate(EAP_VENDOR_ID, EAP_VENDOR_TYPE, reqData, &len);
77 	if (pos == NULL || len < 1) {
78 		ret->ignore = TRUE;
79 		return NULL;
80 	}
81 
82 	if (data->state == INIT && *pos != 1) {
83 		wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Unexpected message "
84 			   "%d in INIT state", *pos);
85 		ret->ignore = TRUE;
86 		return NULL;
87 	}
88 
89 	if (data->state == CONFIRM && *pos != 3) {
90 		wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Unexpected message "
91 			   "%d in CONFIRM state", *pos);
92 		ret->ignore = TRUE;
93 		return NULL;
94 	}
95 
96 	if (data->state == SUCCESS) {
97 		wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Unexpected message "
98 			   "in SUCCESS state");
99 		ret->ignore = TRUE;
100 		return NULL;
101 	}
102 
103 	if (data->state == CONFIRM) {
104 		if (data->test_pending_req && data->first_try) {
105 			data->first_try = 0;
106 			wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Testing "
107 				   "pending request");
108 			ret->ignore = TRUE;
109 			eloop_register_timeout(1, 0, eap_vendor_ready, sm,
110 					       NULL);
111 			return NULL;
112 		}
113 	}
114 
115 	ret->ignore = FALSE;
116 
117 	wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Generating Response");
118 	ret->allowNotifications = TRUE;
119 
120 	resp = eap_msg_alloc(EAP_VENDOR_ID, EAP_VENDOR_TYPE, 1,
121 			     EAP_CODE_RESPONSE, eap_get_id(reqData));
122 	if (resp == NULL)
123 		return NULL;
124 
125 	if (data->state == INIT) {
126 		wpabuf_put_u8(resp, 2);
127 		data->state = CONFIRM;
128 		ret->methodState = METHOD_CONT;
129 		ret->decision = DECISION_FAIL;
130 	} else {
131 		wpabuf_put_u8(resp, 4);
132 		data->state = SUCCESS;
133 		ret->methodState = METHOD_DONE;
134 		ret->decision = DECISION_UNCOND_SUCC;
135 	}
136 
137 	return resp;
138 }
139 
140 
141 static Boolean eap_vendor_test_isKeyAvailable(struct eap_sm *sm, void *priv)
142 {
143 	struct eap_vendor_test_data *data = priv;
144 	return data->state == SUCCESS;
145 }
146 
147 
148 static u8 * eap_vendor_test_getKey(struct eap_sm *sm, void *priv, size_t *len)
149 {
150 	struct eap_vendor_test_data *data = priv;
151 	u8 *key;
152 	const int key_len = 64;
153 
154 	if (data->state != SUCCESS)
155 		return NULL;
156 
157 	key = os_malloc(key_len);
158 	if (key == NULL)
159 		return NULL;
160 
161 	os_memset(key, 0x11, key_len / 2);
162 	os_memset(key + key_len / 2, 0x22, key_len / 2);
163 	*len = key_len;
164 
165 	return key;
166 }
167 
168 
169 int eap_peer_vendor_test_register(void)
170 {
171 	struct eap_method *eap;
172 
173 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
174 				    EAP_VENDOR_ID, EAP_VENDOR_TYPE,
175 				    "VENDOR-TEST");
176 	if (eap == NULL)
177 		return -1;
178 
179 	eap->init = eap_vendor_test_init;
180 	eap->deinit = eap_vendor_test_deinit;
181 	eap->process = eap_vendor_test_process;
182 	eap->isKeyAvailable = eap_vendor_test_isKeyAvailable;
183 	eap->getKey = eap_vendor_test_getKey;
184 
185 	return eap_peer_method_register(eap);
186 }
187