• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "eloop.h"
24 
25 
26 #define EAP_VENDOR_ID 0xfffefd
27 #define EAP_VENDOR_TYPE 0xfcfbfaf9
28 
29 
30 /* #define TEST_PENDING_REQUEST */
31 
32 struct eap_vendor_test_data {
33 	enum { INIT, CONFIRM, SUCCESS } state;
34 	int first_try;
35 };
36 
37 
eap_vendor_test_init(struct eap_sm * sm)38 static void * eap_vendor_test_init(struct eap_sm *sm)
39 {
40 	struct eap_vendor_test_data *data;
41 	data = os_zalloc(sizeof(*data));
42 	if (data == NULL)
43 		return NULL;
44 	data->state = INIT;
45 	data->first_try = 1;
46 	return data;
47 }
48 
49 
eap_vendor_test_deinit(struct eap_sm * sm,void * priv)50 static void eap_vendor_test_deinit(struct eap_sm *sm, void *priv)
51 {
52 	struct eap_vendor_test_data *data = priv;
53 	os_free(data);
54 }
55 
56 
57 #ifdef TEST_PENDING_REQUEST
eap_vendor_ready(void * eloop_ctx,void * timeout_ctx)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 #endif /* TEST_PENDING_REQUEST */
66 
67 
eap_vendor_test_process(struct eap_sm * sm,void * priv,struct eap_method_ret * ret,const u8 * reqData,size_t reqDataLen,size_t * respDataLen)68 static u8 * eap_vendor_test_process(struct eap_sm *sm, void *priv,
69 				    struct eap_method_ret *ret,
70 				    const u8 *reqData, size_t reqDataLen,
71 				    size_t *respDataLen)
72 {
73 	struct eap_vendor_test_data *data = priv;
74 	const struct eap_hdr *req;
75 	struct eap_hdr *resp;
76 	const u8 *pos;
77 	u8 *rpos;
78 	size_t len;
79 
80 	pos = eap_hdr_validate(EAP_VENDOR_ID, EAP_VENDOR_TYPE,
81 			       reqData, reqDataLen, &len);
82 	if (pos == NULL || len < 1) {
83 		ret->ignore = TRUE;
84 		return NULL;
85 	}
86 
87 	if (data->state == INIT && *pos != 1) {
88 		wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Unexpected message "
89 			   "%d in INIT state", *pos);
90 		ret->ignore = TRUE;
91 		return NULL;
92 	}
93 
94 	if (data->state == CONFIRM && *pos != 3) {
95 		wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Unexpected message "
96 			   "%d in CONFIRM state", *pos);
97 		ret->ignore = TRUE;
98 		return NULL;
99 	}
100 
101 	if (data->state == SUCCESS) {
102 		wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Unexpected message "
103 			   "in SUCCESS state");
104 		ret->ignore = TRUE;
105 		return NULL;
106 	}
107 
108 	if (data->state == CONFIRM) {
109 #ifdef TEST_PENDING_REQUEST
110 		if (data->first_try) {
111 			data->first_try = 0;
112 			wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Testing "
113 				   "pending request");
114 			ret->ignore = TRUE;
115 			eloop_register_timeout(1, 0, eap_vendor_ready, sm,
116 					       NULL);
117 			return NULL;
118 		}
119 #endif /* TEST_PENDING_REQUEST */
120 	}
121 
122 	ret->ignore = FALSE;
123 	req = (const struct eap_hdr *) reqData;
124 
125 	wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Generating Response");
126 	ret->allowNotifications = TRUE;
127 
128 	resp = eap_msg_alloc(EAP_VENDOR_ID, EAP_VENDOR_TYPE, respDataLen, 1,
129 			     EAP_CODE_RESPONSE, req->identifier, &rpos);
130 	if (resp == NULL)
131 		return NULL;
132 
133 	if (data->state == INIT) {
134 		*rpos = 2;
135 		data->state = CONFIRM;
136 		ret->methodState = METHOD_CONT;
137 		ret->decision = DECISION_FAIL;
138 	} else {
139 		*rpos = 4;
140 		data->state = SUCCESS;
141 		ret->methodState = METHOD_DONE;
142 		ret->decision = DECISION_UNCOND_SUCC;
143 	}
144 
145 	return (u8 *) resp;
146 }
147 
148 
eap_vendor_test_isKeyAvailable(struct eap_sm * sm,void * priv)149 static Boolean eap_vendor_test_isKeyAvailable(struct eap_sm *sm, void *priv)
150 {
151 	struct eap_vendor_test_data *data = priv;
152 	return data->state == SUCCESS;
153 }
154 
155 
eap_vendor_test_getKey(struct eap_sm * sm,void * priv,size_t * len)156 static u8 * eap_vendor_test_getKey(struct eap_sm *sm, void *priv, size_t *len)
157 {
158 	struct eap_vendor_test_data *data = priv;
159 	u8 *key;
160 	const int key_len = 64;
161 
162 	if (data->state != SUCCESS)
163 		return NULL;
164 
165 	key = os_malloc(key_len);
166 	if (key == NULL)
167 		return NULL;
168 
169 	os_memset(key, 0x11, key_len / 2);
170 	os_memset(key + key_len / 2, 0x22, key_len / 2);
171 	*len = key_len;
172 
173 	return key;
174 }
175 
176 
eap_peer_vendor_test_register(void)177 int eap_peer_vendor_test_register(void)
178 {
179 	struct eap_method *eap;
180 	int ret;
181 
182 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
183 				    EAP_VENDOR_ID, EAP_VENDOR_TYPE,
184 				    "VENDOR-TEST");
185 	if (eap == NULL)
186 		return -1;
187 
188 	eap->init = eap_vendor_test_init;
189 	eap->deinit = eap_vendor_test_deinit;
190 	eap->process = eap_vendor_test_process;
191 	eap->isKeyAvailable = eap_vendor_test_isKeyAvailable;
192 	eap->getKey = eap_vendor_test_getKey;
193 
194 	ret = eap_peer_method_register(eap);
195 	if (ret)
196 		eap_peer_method_free(eap);
197 	return ret;
198 }
199