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