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